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

转载自: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)。

 

 

           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();  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值