Spring AOP使用整理(一)

来源:互联网 发布:淘宝直播运营招聘 编辑:程序博客网 时间:2024/05/18 13:04

关键字: spring, aop

一、基础接口和类

     1、Person接口的源码

Java代码 复制代码
  1. public interface Person {   
  2.     public void info();   
  3.     public void show(String message);   
  4. }  

 

     2、PersonImpl类的源码

Java代码 复制代码
  1. public class PersonImpl implements Person {   
  2.     private String name;   
  3.     private int age;   
  4.        
  5.     public void setName(String name) {   
  6.         this.name = name;   
  7.     }   
  8.   
  9.     public void setAge(int age) {   
  10.         this.age = age;   
  11.     }   
  12.   
  13.     public void info() {   
  14.         System.out.println("/t我叫" + name + ",今年" + age + "岁。");   
  15.     }   
  16.   
  17.     public void show(String message) {   
  18.         System.out.println(message);   
  19.     }   
  20. }  

 

    3、bean的配置

Xml代码 复制代码
  1. <!-- 目标对象 -->  
  2. <bean id="personTarget" class="com.cjm.aop.PersonImpl">  
  3.     <property name="name" value="Raymond.chen"/>  
  4.     <property name="age" value="30"/>  
  5. </bean>  

 

二、Spring AOP支持的通知类型

     一)环绕通知(Around advice)

          实现环绕通知需要实现org.aopalliance.intercept.MethodInterceptor接口。

               1、PersonAroundAdvice类的源码

Java代码 复制代码
  1. public class PersonAroundAdvice implements MethodInterceptor {   
  2.     public Object invoke(MethodInvocation invocation) throws Throwable {   
  3.         System.out.println("AroundAdvice:方法调用前");   
  4.            
  5.         //不要忘记调用invocation的proceed方法哦   
  6.         Object result = invocation.proceed();    
  7.            
  8.         System.out.println("AroundAdvice:方法调用后");   
  9.         return result;   
  10.     }   
  11. }  

 

               2、bean配置

Xml代码 复制代码
  1. <bean id="personAroundAdvice" class="com.cjm.aop.PersonAroundAdvice"/>  
  2.   
  3. <!-- 代理工厂bean -->  
  4. <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">  
  5.     <property name="proxyInterfaces" value="com.cjm.aop.Person"/>  
  6.     <property name="target" ref="personTarget"/>  
  7.     <property name="interceptorNames">  
  8.         <list>  
  9.             <value>personAroundAdvice</value>  
  10.         </list>  
  11.     </property>  
  12. </bean>  

 

               3、测试代码

Java代码 复制代码
  1. ApplicationContext context = new FileSystemXmlApplicationContext("classpath:com/cjm/aop/beans.xml");   
  2. Person p = (Person)context.getBean("person");   
  3. p.info();  

 

     二)前置通知(Before advice)

          实现前置通知需要实现org.springframework.aop.MethodBeforeAdvice接口。

               1、PersonBeforeAdvice类的源码

Java代码 复制代码
  1. public class PersonBeforeAdvice implements MethodBeforeAdvice {   
  2.     public void before(Method method, Object[] args, Object target) throws Throwable {   
  3.         System.out.println("BeforeAdvice:方法调用前");   
  4.     }   
  5. }  

 

               2、bean配置

Xml代码 复制代码
  1. <bean id="personBeforeAdvice" class="com.cjm.aop.PersonBeforeAdvice"/>  
  2.   
  3. <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">  
  4.     <property name="proxyInterfaces" value="com.cjm.aop.Person"/>  
  5.     <property name="target" ref="personTarget"/>  
  6.     <property name="interceptorNames">  
  7.         <list>  
  8.             <value>personBeforeAdvice</value>  
  9.         </list>  
  10.     </property>  
  11. </bean>  

 

     三)返回后通知(After Returning advice)

          实现返回后通知需要实现org.springframework.aop.AfterReturningAdvice接口。

               1、PersonAfterReturningAdvice类的源码

Java代码 复制代码
  1. public class PersonAfterReturningAdvice implements AfterReturningAdvice {   
  2.     public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {   
  3.         System.out.println("AfterReturningAdvice:方法调用后");   
  4.     }   
  5. }  

 

               2、bean配置

Xml代码 复制代码
  1. <bean id="personAfterReturningAdvice" class="com.cjm.aop.PersonAfterReturningAdvice"/>  
  2.   
  3. <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">  
  4.     <property name="proxyInterfaces" value="com.cjm.aop.Person"/>  
  5.     <property name="target" ref="personTarget"/>  
  6.     <property name="interceptorNames">  
  7.         <list>  
  8.             <value>personAfterReturningAdvice</value>  
  9.         </list>  
  10.     </property>  
  11. </bean>  

 

               3、以上的配置中,通知对目标对象的所有方法都会起作用。如果需要过滤掉一部分方法,可以用正则表达式切入点配置器或者方法名匹配切入点配置器实现。

Xml代码 复制代码
  1. <!-- 通知与正则表达式切入点一起配置 -->  
  2. <!-- Advisor等于切入点加通知 -->  
  3. <!-- 方法名匹配切入点配置器:org.springframework.aop.support.NameMatchMethodPointcutAdvisor -->  
  4. <bean id="personPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">  
  5.     <property name="advice" ref="personAfterReturningAdvice"/>  
  6.     <property name="patterns">  
  7.         <list>  
  8.             <value>.*info.*</value>  
  9.         </list>  
  10.     </property>  
  11. </bean>  
  12.   
  13. <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">  
  14.     <property name="proxyInterfaces" value="com.cjm.aop.Person"/>  
  15.     <property name="target" ref="personTarget"/>  
  16.     <property name="interceptorNames">  
  17.         <list>  
  18.             <value>personPointcutAdvisor</value>  
  19.         </list>  
  20.     </property>  
  21. </bean>  

 

     四)异常通知(Throws advice)

          当连接点抛出异常时,异常通知被调用。实现异常通知需要实现org.springframework.aop.ThrowsAdvice接口,该接口不包含任何方法,但在实现该接口时必须实现如下形式的方法:
                 afterThrowing([Method], [args], [target], Throwable subclass)
          可以实现一个或多个这样的方法。在这些方法中,只有第四个参数是必需的,前三个参数可选。

 

          1、PersonThrowsAdvice类的源码

Java代码 复制代码
  1. public class PersonThrowsAdvice implements ThrowsAdvice {   
  2.     public void afterThrowing(FileNotFoundException ex){   
  3.         System.out.println("ThrowsAdvice >> FileNotFoundException:" + ex.toString());   
  4.     }   
  5.   
  6.     public void afterThrowing(Object[] args, Exception ex){   
  7.         System.out.println("ThrowsAdvice >> Exception:" + ex.getMessage());   
  8.     }   
  9.   
  10.     public void afterThrowing(Method method, Object[] args, Object target, Throwable ex){   
  11.         System.out.println("ThrowsAdvice >> Throwable:" + ex.getMessage());   
  12.     }   
  13. }  

 

          2、bean配置

Xml代码 复制代码
  1. <bean id="personThrowsAdvice" class="com.cjm.aop.PersonThrowsAdvice"/>  
  2.   
  3. <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">  
  4.     <property name="proxyInterfaces" value="com.cjm.aop.Person"/>  
  5.     <property name="target" ref="personTarget"/>  
  6.     <property name="interceptorNames">  
  7.         <list>  
  8.             <value>personThrowsAdvice</value>  
  9.         </list>  
  10.     </property>  
  11. </bean>  

 

     五)引入通知(Introduction advice)

           引入通知是一种特殊的通知,它能将新的成员变量、成员方法引入到目标类中。它不能作用于任何切入点,因为它只作用于类层次,而不是方法层次。实现引入通知需要实现IntroductionAdvisor和IntroductionInterceptor接口。

           引入通知不能调用proceed方法。Advisor必须针对每个实例,并且是有状态的。

           引入通知的效果类似于设计模式中的访问者模式(Visitor Pattern)。

 

 

           1、Lockable接口的源码

Java代码 复制代码
  1. public interface Lockable {   
  2.     void lock();   
  3.     void unlock();   
  4.     boolean locked();   
  5. }  

 

           2、LockableImpl类的源码

Java代码 复制代码
  1. public class LockableImpl extends DelegatingIntroductionInterceptor implements Lockable {   
  2.     private boolean locked;   
  3.        
  4.     public void lock() {   
  5.         this.locked = true;   
  6.     }   
  7.   
  8.     public void unlock() {   
  9.         this.locked = false;   
  10.     }   
  11.   
  12.     public boolean locked() {   
  13.         return this.locked;   
  14.     }   
  15.   
  16.     @Override  
  17.     public Object invoke(MethodInvocation invocation) throws Throwable {   
  18.         if(this.locked){   
  19.             throw new RuntimeException("加锁,无法执行");   
  20.         }   
  21.            
  22.         //这里不能调用invocation的proceed方法   
  23.         //通常不需要改写invoke方法,直接调用父类的该方法即可   
  24.         return super.invoke(invocation);   
  25.     }   
  26. }  

 

           3、PersonIntroductionAdvice类的源码

Java代码 复制代码
  1. public class PersonIntroductionAdvice extends DefaultIntroductionAdvisor {   
  2.     public PersonIntroductionAdvice(){   
  3.         super(new LockableImpl(), Lockable.class);   
  4.     }   
  5. }  

 

           4、bean配置

Xml代码 复制代码
  1. <!-- Advice必须针对每个实例,所以scope要设为prototype -->  
  2. <bean id="personIntroductionAdvice" class="com.cjm.aop.introduction.PersonIntroductionAdvice" scope="prototype"/>  
  3.   
  4. <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">  
  5.     <property name="proxyInterfaces" value="com.cjm.aop.Person"/>  
  6.     <property name="target" ref="personTarget"/>  
  7.     <property name="interceptorNames">  
  8.         <list>  
  9.             <value>personIntroductionAdvice</value>  
  10.         </list>  
  11.     </property>  
  12. </bean>  

 

           5、测试代码

Java代码 复制代码
  1. ApplicationContext context = new FileSystemXmlApplicationContext("classpath:com/cjm/aop/beans.xml");   
  2.   
  3. //获得目标bean的代理bean   
  4. Person p = (Person)context.getBean("person");   
  5.   
  6. //执行代理bean的方法,此时并未调用lock方法,可以执行   
  7. p.info();   
  8.   
  9. Lockable lockable = (Lockable)p;   
  10. lockable.lock();   
  11.   
  12. //目标bean已被锁定,此处将抛出异常   
  13. p.info();