面向切面的Spring
在一般的程序開(kāi)發(fā)中,在每一個(gè)功能模塊中都有相同的操作,例如打印日志,事務(wù)操作等一系列重復(fù)動(dòng)作,而Spring AOP指的就是把這種重復(fù)工作橫向抽取出來(lái),讓程序員只需要關(guān)注業(yè)務(wù)
下面是關(guān)于AOP的相關(guān)術(shù)語(yǔ)
通知:簡(jiǎn)而言之就是被抽取出來(lái)的方法
連接點(diǎn):可以插入通知的點(diǎn)
切點(diǎn):需要被插入通知的點(diǎn)
切面:切點(diǎn)和通知構(gòu)成了一個(gè)切面
織入:把切面應(yīng)用到目標(biāo)對(duì)象并創(chuàng)建新的代理對(duì)象過(guò)程
使用注解的方式定義切面
可以在類前使用@Aspect,代表這個(gè)是個(gè)切面類,一下代表的是在perform方法調(diào)用之前執(zhí)行這個(gè)方法
@Aspect
public class Audience{
@Before("execution (** concert.Performace.perform(..))")
public void silenceCellPhones(){
System.out.prinln("Silencing cell phones");
}
}
如果相同的切點(diǎn)被頻繁的使用,可以使用@pointcut,被定義為@Pointcut的實(shí)際方法內(nèi)容不重要,他只是作為一個(gè)標(biāo)識(shí)
public class Audience{
@Pointcut("execution (** concert.Performance.perform(..))")
public void performance(){}
@Before("performance()")
public void silenceCellPhones(){
System.out.println("aa");
}
}
定義了切面類以后,需要使用配置來(lái)自動(dòng)裝配被@Aspect修飾的類
使用JavaConfig啟動(dòng)自動(dòng)代理
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class ConcertConfig{
@Bean
public Audience audience(){
return new Audience();
}
}
使用xml
<context:component-scan base-package="concert" />
<aop:aspectj-autoproxy /> 啟動(dòng)AspectJ自動(dòng)代理
在xml中聲明切面
在前面所說(shuō)的切面定義中,使用java配置優(yōu)于xml配置,但是java配置的缺點(diǎn)就是必須要有源碼,所以,了解在xml中聲明切面是必須的
<aop:config>
<aop:aspect ref="Bean"> <!--引用一個(gè)切面類-->
<!--before 前置通知-->
<!--pointcut切入點(diǎn),代表需要被插入通知的方法的地方-->
<!--method 通知,代表插入的方法 -->
<aop:before
pointcut="execution(** 包名.類名.方法名(..))"
method="insertMethod" //通知
/>
同理 before改成after-returning代表后置通知,且方法被執(zhí)行完成以后才會(huì)執(zhí)行
after代表無(wú)論方法是否執(zhí)行成功都會(huì)執(zhí)行
after-thorwing代表拋出異常以后會(huì)執(zhí)行的方法
</aop:config>
如果多個(gè)通知都是在同一個(gè)切點(diǎn),這樣就要重復(fù)寫很多同樣的pointcut,我們可以為切點(diǎn)命名,如下,這樣我們就可以使用pointcut-ref直接指定id號(hào)獲取切點(diǎn),如果想要這個(gè)切點(diǎn)可以被所有切面所引用,可以把這個(gè)節(jié)點(diǎn)放在config下
<aop:config>
<aop:aspect ref="audience">
<aop:pointcut id="idName" expression="execution ..."
</aop:aspect>
</aop:config>
環(huán)繞通知
環(huán)繞通知指的是 既可以執(zhí)行前置通知 然后在執(zhí)行被通知方法,最后在執(zhí)行后置通知,環(huán)繞通知的好處是因?yàn)榄h(huán)繞通知是一個(gè)方法,所以變量是共享的,如果使用前置和后置通知,你在前置通知中定義的變量肯定是不能被后置通知訪問(wèn)的
環(huán)繞通知必須有參數(shù),因?yàn)樾枰{(diào)用被通知函數(shù)
public void roundMethod(ProceedingJoinPoint jp){
try{
//前置方法
System.out.println("前置方法")
jp.proceed();//調(diào)用被通知方法
System.out.println("后置方法")
}catch(Exception e){
System.out.println("異常之后的方法");
}
}
<aop:config>
<aop:aspect ref="aspectBean">
<aop:pointcut id="idName"
expression ="execution(** 包名.類名.方法(..))"
method ="roundMethod"
</aop:aspect>
<aop:config>
通過(guò)以上就可以達(dá)到前置、后置、異常的通知 織入到切點(diǎn)中