Spring AOP使用整理:各种通知类型的介绍

系统 1644 0

转载自: http://chenjumin.iteye.com/blog/364948

 

一、基础接口和类

     1、Person接口的源码

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

 

     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. }  
      public class PersonImpl implements Person {
	private String name;
	private int age;
	
	public void setName(String name) {
		this.name = name;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public void info() {
		System.out.println("\t我叫" + name + ",今年" + age + "岁。");
	}

	public void show(String message) {
		System.out.println(message);
	}
}

    

 

    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 >   
      <!-- 目标对象 -->
<bean id="personTarget" class="com.cjm.aop.PersonImpl">
	<property name="name" value="Raymond.chen"/>
	<property name="age" value="30"/>
</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. }  
      public class PersonAroundAdvice implements MethodInterceptor {
	public Object invoke(MethodInvocation invocation) throws Throwable {
		System.out.println("AroundAdvice:方法调用前");
		
		//不要忘记调用invocation的proceed方法哦
		Object result = invocation.proceed(); 
		
		System.out.println("AroundAdvice:方法调用后");
		return result;
	}
}

    

 

               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 >   
      <bean id="personAroundAdvice" class="com.cjm.aop.PersonAroundAdvice"/>

<!-- 代理工厂bean -->
<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="proxyInterfaces" value="com.cjm.aop.Person"/>
	<property name="target" ref="personTarget"/>
	<property name="interceptorNames">
		<list>
			<value>personAroundAdvice</value>
		</list>
	</property>
</bean>

    

 

               3、测试代码

Java代码 复制代码   收藏代码
  1. ApplicationContext context =  new  FileSystemXmlApplicationContext( "classpath:com/cjm/aop/beans.xml" );  
  2. Person p = (Person)context.getBean( "person" );   //注意这里是代理工厂Bean的ID   
  3. p.info();  
      ApplicationContext context = new FileSystemXmlApplicationContext("classpath:com/cjm/aop/beans.xml");
Person p = (Person)context.getBean("person");  //注意这里是代理工厂Bean的ID
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. }  
      public class PersonBeforeAdvice implements MethodBeforeAdvice {
	public void before(Method method, Object[] args, Object target) throws Throwable {
		System.out.println("BeforeAdvice:方法调用前");
	}
}

    

 

               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 >   
      <bean id="personBeforeAdvice" class="com.cjm.aop.PersonBeforeAdvice"/>

<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="proxyInterfaces" value="com.cjm.aop.Person"/>
	<property name="target" ref="personTarget"/>
	<property name="interceptorNames">
		<list>
			<value>personBeforeAdvice</value>
		</list>
	</property>
</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. }  
      public class PersonAfterReturningAdvice implements AfterReturningAdvice {
	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
		System.out.println("AfterReturningAdvice:方法调用后");
	}
}

    

 

               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 >   
      <bean id="personAfterReturningAdvice" class="com.cjm.aop.PersonAfterReturningAdvice"/>

<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="proxyInterfaces" value="com.cjm.aop.Person"/>
	<property name="target" ref="personTarget"/>
	<property name="interceptorNames">
		<list>
			<value>personAfterReturningAdvice</value>
		</list>
	</property>
</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 >   
      <!-- 通知与正则表达式切入点一起配置 -->
<!-- Advisor等于切入点加通知 -->
<!-- 方法名匹配切入点配置器:org.springframework.aop.support.NameMatchMethodPointcutAdvisor -->
<bean id="personPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
	<property name="advice" ref="personAfterReturningAdvice"/>
	<property name="patterns">
		<list>
			<value>.*info.*</value>
		</list>
	</property>
</bean>

<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="proxyInterfaces" value="com.cjm.aop.Person"/>
	<property name="target" ref="personTarget"/>
	<property name="interceptorNames">
		<list>
			<value>personPointcutAdvisor</value>
		</list>
	</property>
</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. }  
      public class PersonThrowsAdvice implements ThrowsAdvice {
	public void afterThrowing(FileNotFoundException ex){
		System.out.println("ThrowsAdvice >> FileNotFoundException:" + ex.toString());
	}

	public void afterThrowing(Object[] args, Exception ex){
		System.out.println("ThrowsAdvice >> Exception:" + ex.getMessage());
	}

	public void afterThrowing(Method method, Object[] args, Object target, Throwable ex){
		System.out.println("ThrowsAdvice >> Throwable:" + ex.getMessage());
	}
}

    

 

          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 >   
      <bean id="personThrowsAdvice" class="com.cjm.aop.PersonThrowsAdvice"/>

<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="proxyInterfaces" value="com.cjm.aop.Person"/>
	<property name="target" ref="personTarget"/>
	<property name="interceptorNames">
		<list>
			<value>personThrowsAdvice</value>
		</list>
	</property>
</bean>

    

 

     五)引入通知(Introduction advice)

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

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

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

 

Spring AOP使用整理:各种通知类型的介绍

 

           1、Lockable接口的源码

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

    

 

           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. }  
      public class LockableImpl extends DelegatingIntroductionInterceptor implements Lockable {
	private boolean locked;
	
	public void lock() {
		this.locked = true;
	}

	public void unlock() {
		this.locked = false;
	}

	public boolean locked() {
		return this.locked;
	}

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		if(this.locked){
			throw new RuntimeException("加锁,无法执行");
		}
		
		//这里不能调用invocation的proceed方法
		//通常不需要改写invoke方法,直接调用父类的该方法即可
		return super.invoke(invocation);
	}
}

    

 

           3、PersonIntroductionAdvice类的源码

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

    

 

           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 >   
      <!-- Advice必须针对每个实例,所以scope要设为prototype -->
<bean id="personIntroductionAdvice" class="com.cjm.aop.introduction.PersonIntroductionAdvice" scope="prototype"/>

<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="proxyInterfaces" value="com.cjm.aop.Person"/>
	<property name="target" ref="personTarget"/>
	<property name="interceptorNames">
		<list>
			<value>personIntroductionAdvice</value>
		</list>
	</property>
</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();  

Spring AOP使用整理:各种通知类型的介绍


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论