Spring整合aspectj框架實現的aop
Spring整合aspectj框架實現的aop
在現在的開發中使用這種方案比較多.
在spring2.0以後它支援jdk1.5註解,而整合aspectj後可以使用aspectj語法,可以簡化開發。
Aspect:切面 =切點+通知(多個切點與多個通知的組合)
AspectJ它是一個第三方框架,spring從2.0後可以使用aspectJ框架的部分語法.
AspectJ框架它定義的通知型別有6種
1.前置通知Before相當於BeforeAdvice
2.後置通知AfterReturning相當於AfterReturningAdvice
3.環繞通知
Around 相當於MethodInterceptor
4.丟擲通知AfterThrowing相當於ThrowAdvice
5.引介通知DeclareParents相當於IntroductionInterceptor
6.最終通知After不管是否異常,該通知都會執行
相比spring的傳統AOP Advice多了一個最終通知
第一步:建立目標(target)
public class UserServiceImpl implements UserService { @Override public int add() { int a = 10 / 0; System.out.println("add......"); return 66; } @Override public void del() { System.out.println("del......"); } @Override public void update() { System.out.println("update......"); } @Override public void find() { System.out.println("find......"); } }
第二步:建立通知(增強 advice)
注意:在aspectj中它的增強可以不實現任何介面,只需要定義出增強功能(方法)
//advice public class UserServiceHelper{ //前置通知+引數 public void before(JoinPoint jp){ System.out.println("攔截的目標類" + jp.getSignature().getDeclaringTypeName()); System.out.println("攔截的方法" + jp.getSignature().getName()); System.out.println("前置......"); } //後置通知 public void after(JoinPoint jp , Object val){ System.out.println("返回值為" + val); System.out.println("後置....."); } //環繞通知 public Object around(ProceedingJoinPoint pip) throws Throwable{ System.out.println("環繞前"); Object proceed = pip.proceed(); System.out.println("環繞後"); return proceed; } //異常丟擲通知 public void afterThrowing(JoinPoint jp,Throwable ex){ System.out.println(ex); System.out.println("發現異常"); } //最終通知 public void end(JoinPoint jp){ System.out.println(jp.getSignature().getName()); System.out.println("結束"); }
第三步:在spring的xml配置檔案中來配置
<aop:config>下的<aop:aspect>是aspectJ框架用來宣告切面的。
applicationContext.xml配置檔案
<aop:config>
<aop:aspect ref="userServiceAdvice">
<aop:pointcut expression="execution(* com.itheima.aspectj.* .*(..))" id="myPointCut"/>
<aop:before method="before" pointcut-ref="myPointCut" /> 前置
<aop:after-returning method="after" pointcut-ref="myPointCut" /> 後置
<aop:around method="around" pointcut-ref="myPointCut"/> 環繞
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointCut"/> 發現異常
<aop:after method="end" pointcut-ref="myPointCut"/> 最終
</aop:aspect>
</aop:config>
測試程式碼
//前置通知
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AspectjTest {
@Autowired
private UserService userService;
@Test
public void test(){
userService.del();
}
加引數
public class UserServiceHelper {
//前置通知+引數
public void before(JoinPoint jp){
System.out.println("攔截的目標類" + jp.getSignature().getDeclaringTypeName());
System.out.println("攔截的方法" + jp.getSignature().getName());
System.out.println("前置......");
}
//後置通知
public void after(JoinPoint jp , Object val){
System.out.println("返回值為" + val);
System.out.println("後置.....");
}
//環繞通知
public Object around(ProceedingJoinPoint pip) throws Throwable{
System.out.println("環繞前");
Object proceed = pip.proceed();
System.out.println("環繞後");
return proceed;
}
//異常丟擲通知
public void afterThrowing(JoinPoint jp,Throwable ex){
System.out.println(ex);
System.out.println("發現異常");
}
//最終通知
public void end(JoinPoint jp){
System.out.println(jp.getSignature().getName());
System.out.println("結束");
}
applicationContext.xml
<aop:config>
<aop:aspect ref="userServiceAdvice">
<aop:pointcut expression="execution(* com.itheima.aspectj.* .*(..))" id="myPointCut"/>
<aop:before method="before" pointcut-ref="myPointCut" /> 前置
<aop:after-returning method="after" pointcut-ref="myPointCut" returning="val" /> 後置
<aop:around method="around" pointcut-ref="myPointCut"/> 環繞
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointCut" throwing="ex"/> 發現異常
<aop:after method="end" pointcut-ref="myPointCut"/> 最終
</aop:aspect>
</aop:config>
關於代理方式選擇
在spring的aop開發中,它使用的是代理方案,代理實現有兩種:
1. jdk的proxy
2. cglib
spring框架預設情況下,會對有介面的類使用proxy代理。沒有介面的類使用cglib代理
如果為false 那麼如果有實現介面那麼為jdk的proxy 沒有介面則為cglib
如果為true 那麼不管有沒有實現介面預設為cglib
Proxy-target-class的值預設是false,它代表有介面使用proxy代理
問題:如果現在對目標要使用cglib代理(不考慮是否有介面)?
只需要將proxy-target-class設定為true.