SpringAOP实例自定义Annotation形式详解

    Spring除了支持Schema方式配置AOP,还支持注解方式:使用@AspectJ风格的切面声明。

   1  启用对@AspectJ的支持

       spring默认不支持@AspectJ风格的切面声明,为了支持需要使用如下配置:

 

 

[html]  view plain  copy
  1. <!-- 开启支持@AspectJ风格的切面声明 -->  
  2. <aop:aspectj-autoproxy/></span>  

 

 

 

这样Spring就能发现@AspectJ风格的切面并且将切面应用到目标对象。

  2  声明切面

       @AspectJ风格的声明切面非常简单,使用@Aspect注解进行声明:

     

[html]  view plain  copy
  1. package zmx.spring.aop.test;  
  2.   
  3. import org.aspectj.lang.annotation.After;  
  4. import org.aspectj.lang.annotation.Aspect;  
  5. import org.aspectj.lang.annotation.Before;  
  6. import org.aspectj.lang.annotation.Pointcut;  
  7. //定义切面  
  8. @Aspect()  
  9. public class LoggerAspect {  
  10.       
  11.     //定义切入点  
  12.     @Pointcut(value="execution(* zmx.spring.aop.test..*.*(..)) && args(param)"argNames = "param")    
  13.     public void beforePointcut(String param) {}  
  14.       
  15.       
  16.     @Pointcut(value="execution(* zmx.spring.aop.test..*.*(..))")    
  17.     public void afterPointcut(){}  
  18.   
  19.       
  20.     //定义通知  
  21.       
  22.     //前置日志通知   
  23.     @Before(value = "beforePointcut(param)"argNames = "param")    
  24.     public void beforeAdvice(String param) {    
  25.           System.out.println("===========before advice param:" + param);    
  26.     }   
  27.     
  28.     //后置日志通知   
  29.     @After(value = "afterPointcut()")  
  30.     public void afterAdvice() {    
  31.         System.out.println("===========after advice param");    
  32.     }  
  33.   
  34.   
  35. }  

 

       然后将该切面在配置文件中声明为Bean后,Spring就能自动识别并进行AOP方面的配置:

 

[html]  view plain  copy
  1. <!-- 切面 -->   
  2. <bean id="loggerAspect"  class="zmx.spring.aop.test.LoggerAspect"  />  
[html]  view plain  copy
  1. <span style="font-size:12px;">     该切面就是一个POJO,可以在该切面中进行切入点及通知定义,接着往下看吧。</span>  

 

3  声明切入点

       @AspectJ风格的命名切入点使用org.aspectj.lang.annotation包下的@Pointcut+方法(方法必须是返回void类型)实现。

 

java代码:
  1. @Pointcut(value="切入点表达式", argNames = "参数名列表")  
  2. public void pointcutName(……) {}  
  3.    

       value:指定切入点表达式;

       argNames:指定命名切入点方法参数列表参数名字,可以有多个用“,”分隔,这些参数将传递给通知方法同名的参数,同时比如切入点表达式“args(param)”将匹配参数类型为命名切入点方法同名参数指定的参数类型。

       pointcutName:切入点名字,可以使用该名字进行引用该切入点表达式。

 

java代码:
  1. @Pointcut(value="execution(* cn.javass..*.sayAdvisorBefore(..)) && args(param)", argNames = "param")  
  2. public void beforePointcut(String param) {}  

 

定义了一个切入点,名字为“beforePointcut”,该切入点将匹配目标方法的第一个参数类型为通知方法实现中参数名为“param”的参数类型。

4  声明通知

       @AspectJ风格的声明通知也支持5种通知类型:

 

一、前置通知:使用org.aspectj.lang.annotation 包下的@Before注解声明;

 

java代码:
  1. @Before(value = "切入点表达式或命名切入点", argNames = "参数列表参数名")  

 

       value:指定切入点表达式或命名切入点;

       argNames:与Schema方式配置中的同义。

 

 5 实例

接下来示例一下吧:

1、定义接口和实现,在此我们就使用Schema风格时的定义;

接口:

[html]  view plain  copy
  1. package zmx.spring.aop.test;  
  2.   
  3. public interface  IHelloWorldService {  
  4.       
  5.     public void sayHello();   
  6.       
  7.     public void recordLog(String log);  
  8.   
  9. }  

实现:

[html]  view plain  copy
  1. package zmx.spring.aop.test;  
  2.   
  3. public class HelloWorldService implements IHelloWorldService {  
  4.   
  5.     @Override  
  6.     public void sayHello() {  
  7.          System.out.println("============Hello World!================");      
  8.     }  
  9.   
  10.     @Override  
  11.     public void recordLog(String log) {  
  12.           
  13.          System.out.println("============record Log================"+log);  
  14.     }  
  15.       
  16.       
  17.   
  18. }  

 

2、定义切面: 

3、定义切入点: 

4、定义通知:

 

[html]  view plain  copy
  1. package zmx.spring.aop.test;  
  2.   
  3. import org.aspectj.lang.annotation.After;  
  4. import org.aspectj.lang.annotation.Aspect;  
  5. import org.aspectj.lang.annotation.Before;  
  6. import org.aspectj.lang.annotation.Pointcut;  
  7. //2、定义切面  
  8. @Aspect()  
  9. public class LoggerAspect {  
  10.       
  11.     //3、定义切入点  
  12.     @Pointcut(value="execution(* zmx.spring.aop.test..*.*(..)) && args(param)"argNames = "param")    
  13.     public void beforePointcut(String param) {}  
  14.       
  15.       
  16.     @Pointcut(value="execution(* zmx.spring.aop.test..*.*(..))")    
  17.     public void afterPointcut(){}  
  18.   
  19.       
  20.     //4、定义通知  
  21.       
  22.     //前置日志通知   
  23.     @Before(value = "beforePointcut(param)"argNames = "param")    
  24.     public void beforeAdvice(String param) {    
  25.           System.out.println("===========before advice param:" + param);    
  26.     }   
  27.     
  28.     //后置日志通知   
  29.     @After(value = "afterPointcut()")  
  30.     public void afterAdvice() {    
  31.         System.out.println("===========after advice param");    
  32.     }  
  33.   
  34.   
  35. }  
[html]  view plain  copy
  1. 5、在配置文件中进行如下配置  
[html]  view plain  copy
  1. <?xml version="1.0" encoding="UTF-8" standalone="no"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:aop="http://www.springframework.org/schema/aop"  
  4.        xmlns:context="http://www.springframework.org/schema/context"  
  5.        xmlns:jee="http://www.springframework.org/schema/jee"   
  6.        xmlns:tx="http://www.springframework.org/schema/tx"  
  7.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  8.        xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd     
  9.        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     
  10.        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd     
  11.        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd     
  12.        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">  
  13.        
  14.      <!-- 开启支持@AspectJ风格的切面声明 -->  
  15.      <aop:aspectj-autoproxy/>   
  16.        
  17.         
  18.        
  19.      <!-- 目标对象 -->   
  20.      <bean id="helloWorldService"  class="zmx.spring.aop.test.HelloWorldService"  />  
  21.       
  22.      <!-- 切面 -->   
  23.      <bean id="loggerAspect"  class="zmx.spring.aop.test.LoggerAspect"  />  
  24.       
  25.       
  26.       
  27.     
  28.       
  29.   
  30.       
  31. </beans>  


 

6、测试代码:

 

[html]  view plain  copy
  1. package zmx.spring.aop.test;  
  2.   
  3. import org.junit.Test;  
  4. import org.springframework.context.ApplicationContext;  
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  6.   
  7. public class MainTest {  
  8.     @Test  
  9.     public void testHelloWorld(){  
  10.           
  11.             ApplicationContext ctx = new ClassPathXmlApplicationContext("zmx/spring/applicationContext.xml");  
  12.             IHelloWorldService helloworldService = ctx.getBean("helloWorldService", IHelloWorldService.class);    
  13.             helloworldService.recordLog("日志");  
  14.           
  15.     }  
  16.       
  17.   
  18.   
  19. }  


 

 

将输出:

===========before advice param:日志

============recordLog================日志

===========after advice param</span>

 

 

  

 

切面、切入点、通知全部使用注解完成:

       1)使用@Aspect将POJO声明为切面;

       2)使用@Pointcut进行命名切入点声明,同时指定目标方法第一个参数类型必须是Java.lang.String,对于其他匹配的方法但参数类型不一致的将也是不匹配的,通过argNames = "param"指定了将把该匹配的目标方法参数传递给通知同名的参数上;

       3)使用@Before进行前置通知声明,其中value用于定义切入点表达式或引用命名切入点;

       4)配置文件需要使用<aop:aspectj-autoproxy/>来开启注解风格的@AspectJ支持;

       5)需要将切面注册为Bean,如“aspect”Bean;

       6)测试代码完全一样。

 

 

二、后置返回通知:使用org.aspectj.lang.annotation 包下的@AfterReturning注解声明;

 

java代码:
  1. @AfterReturning(  
  2. value="切入点表达式或命名切入点",  
  3. pointcut="切入点表达式或命名切入点",  
  4. argNames="参数列表参数名",  
  5. returning="返回值对应参数名")  

       value:指定切入点表达式或命名切入点;

       pointcut:同样是指定切入点表达式或命名切入点,如果指定了将覆盖value属性指定的,pointcut具有高优先级;

       argNames:与Schema方式配置中的同义;

       returning:与Schema方式配置中的同义。

 

 

java代码:
  1. @AfterReturning(  
  2.     value="execution(* cn.javass..*.sayBefore(..))",  
  3.     pointcut="execution(* cn.javass..*.sayAfterReturning(..))",  
  4.     argNames="retVal", returning="retVal")  
  5. public void afterReturningAdvice(Object retVal) {  
  6.     System.out.println("===========after returning advice retVal:" + retVal);  
  7. }  

 

其中测试代码与Schema方式几乎一样,在此就不演示了,如果需要请参考AopTest.java中的testAnnotationAfterReturningAdvice测试方法。

 

三、后置异常通知:使用org.aspectj.lang.annotation 包下的@AfterThrowing注解声明;

 

java代码:
  1. @AfterThrowing (  
  2. value="切入点表达式或命名切入点",  
  3. pointcut="切入点表达式或命名切入点",  
  4. argNames="参数列表参数名",  
  5. throwing="异常对应参数名")  
  6.    

 

       value:指定切入点表达式或命名切入点;

       pointcut:同样是指定切入点表达式或命名切入点,如果指定了将覆盖value属性指定的,pointcut具有高优先级;

       argNames:与Schema方式配置中的同义;

       throwing:与Schema方式配置中的同义。

 

 

java代码:
  1. @AfterThrowing(  
  2.     value="execution(* cn.javass..*.sayAfterThrowing(..))",  
  3.     argNames="exception", throwing="exception")  
  4. public void afterThrowingAdvice(Exception exception) {  
  5.     System.out.println("===========after throwing advice exception:" + exception);  
  6. }  

 

其中测试代码与Schema方式几乎一样,在此就不演示了,如果需要请参考AopTest.java中的testAnnotationAfterThrowingAdvice测试方法。

 

四、后置最终通知:使用org.aspectj.lang.annotation 包下的@After注解声明;

 

java代码:
  1. @After (  
  2. value="切入点表达式或命名切入点",  
  3. argNames="参数列表参数名")  

       value:指定切入点表达式或命名切入点;

       argNames:与Schema方式配置中的同义;

 

 

java代码:
  1. @After(value="execution(* cn.javass..*.sayAfterFinally(..))")  
  2. public void afterFinallyAdvice() {  
  3.     System.out.println("===========after finally advice");  
  4. }  

 

其中测试代码与Schema方式几乎一样,在此就不演示了,如果需要请参考AopTest.java中的testAnnotationAfterFinallyAdvice测试方法。

 

 

五、环绕通知:使用org.aspectj.lang.annotation 包下的@Around注解声明;

 

java代码:
  1. @Around (  
  2. value="切入点表达式或命名切入点",  
  3. argNames="参数列表参数名")  

 

       value:指定切入点表达式或命名切入点;

       argNames:与Schema方式配置中的同义;

 

 

java代码:
  1. @Around(value="execution(* cn.javass..*.sayAround(..))")  
  2. public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {  
  3.     System.out.println("===========around before advice");  
  4.     Object retVal = pjp.proceed(new Object[] {"replace"});  
  5.     System.out.println("===========around after advice");  
  6.     return retVal;  
  7. }  

 

 

其中测试代码与Schema方式几乎一样,在此就不演示了,如果需要请参考AopTest.java中的annotationAroundAdviceTest测试方法。

6.4.5  引入

       @AspectJ风格的引入声明在切面中使用org.aspectj.lang.annotation包下的@DeclareParents声明:

 

java代码:
  1. @DeclareParents(  
  2. value=" AspectJ语法类型表达式",  
  3. defaultImpl=引入接口的默认实现类)  
  4. private Interface interface;  

 

       value:匹配需要引入接口的目标对象的AspectJ语法类型表达式;与Schema方式中的types-matching属性同义;

       private Interface interface指定需要引入的接口;

       defaultImpl指定引入接口的默认实现类,没有与Schema方式中的delegate-ref属性同义的定义方式;

 

java代码:
  1. @DeclareParents(  
  2.     value="cn.javass..*.IHelloWorldService+", defaultImpl=cn.javass.spring.chapter6.service.impl.IntroductiondService.class)  
  3. private IIntroductionService introductionService;  
  4.    

 

       其中测试代码与Schema方式几乎一样,在此就不演示了,如果需要请参考AopTest.java中的testAnnotationIntroduction测试方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值