`

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();  
分享到:
评论

相关推荐

    Spring学习篇AOP知识整理编程开发技术共4页.pdf

    Spring支持五种不同类型的通知:前置通知(Before)、后置通知(After)、返回通知(After Returning)、异常通知(After Throwing)和环绕通知(Around)。 3. **连接点(Join Point)**:连接点是在应用程序执行...

    Spring IOC和AOP代码与笔记整理

    5. **代理(Proxy)**:Spring AOP通过JDK动态代理或CGLIB代理来创建一个目标对象的代理,以便在调用目标方法时插入通知。 实际操作中,我们可以使用注解来声明切面,例如`@Aspect`、`@Before`、`@After`等,也可以...

    个人整理的关于AOP概念

    在Spring框架中,AOP的实现不仅增强了应用程序的灵活性,还提供了丰富的通知类型,便于开发者根据不同场景选择最合适的通知策略,从而构建更加高效、健壮的系统。理解并掌握AOP的概念和机制,对提高软件开发效率和...

    Aop记录执行时间.pdf

    Spring AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架的重要特性之一,它能够让我们在不修改原有代码的情况下,给程序中的一些功能增加额外的行为,例如日志、事务管理等。通过AOP,开发者可以将横...

    spring知识点代码示例整理

    - `spring_aop_annotation` 文件夹包含的是使用注解方式实现的 AOP 示例。在 Spring 中,AOP 允许开发者定义“切面”,将关注点(如日志、事务管理)与业务逻辑分离。通过 @Aspect 注解定义切面,@Before、@After、...

    尚硅谷佟刚Spring完整代码

    "尚硅谷佟刚Spring完整代码"是一个集合了全面Spring框架示例和教程的资源包,旨在帮助学习者深入理解和实践Spring框架的各种功能。这个压缩包包含的文件是开发者为了补充尚硅谷官网上的Spring代码而精心整理和完善的...

    Spring基础学习资料,很全面,很经典,手工整理,适合刚学习spring的同学

    Spring框架是Java开发中的核心组件,它以依赖注入(Dependency Injection, DI)和面向切面编程(Aspect-Oriented Programming, AOP)为核心,极大地简化了企业级应用的开发过程。这份“Spring基础学习资料”涵盖了...

    Spring学习思维笔记.rar

    4. **AOP**:Spring的AOP允许开发者定义“切面”,这些切面可以包含通知(advice),即在特定连接点(join point)执行的代码,比如方法调用前或后。AOP用于日志记录、事务管理、权限检查等场景。 5. **数据访问...

    spring的学习笔记

    Spring框架是Java开发中广泛使用的轻量级框架,以其依赖注入(Dependency Injection,简称DI)和面向切面编程(Aspect-Oriented Programming,简称AOP)的核心特性,极大地简化了企业级应用的开发。以下是对Spring...

    Spring源码解析.zip

    通过阅读源码,我们可以学习如何定义切面、切入点表达式和通知类型,并理解Spring如何在运行时生成代理对象以实现AOP功能。 再者,Spring的事务管理也是其关键特性之一。Spring提供了编程式和声明式事务管理两种...

    Spring 面试题和答案.zip

    Spring框架是Java开发中不可或缺的一部分,它以其强大的依赖注入(DI)和面向切面编程(AOP)功能而闻名。面试中,Spring相关的知识点通常包括其核心概念、配置方式、AOP原理、事务管理、MVC模块、Spring Boot以及...

    Spring面试专题及答案整理文档.zip

    这个“Spring面试专题及答案整理文档”包含了Spring框架的重要知识点,是准备Spring面试和深入理解Spring技术体系的良好资料。 1. **依赖注入(DI)** - DI是Spring的核心,它允许开发者在运行时通过XML配置或注解...

    spring-reference---cn

    根据提供的信息,我们可以推断这份文档是关于Spring框架的一个中文参考文档,主要涵盖了Spring的核心概念和技术要点。下面将根据给出的信息来整理并扩展...希望以上整理的知识点能帮助您更好地理解和使用Spring框架。

    spring源码学习

    标签中提到了“源码”和“工具”,这意味着内容可能包含如何使用各种工具(如IDEA、Git等)来阅读和理解Spring的源代码。源码阅读对于开发者来说是一项重要技能,它涉及理解类结构、方法调用、设计模式等。而工具的...

    Spring相关资料

    根据提供的文件内容,我们可以整理出一系列与Spring框架相关的知识点,涉及Spring的基本概念、Spring与其它技术的集成方式、以及Spring支持的各种模式等。下面将详细展开这些知识点。 ### Spring框架概述 Spring是...

    spring mvc需要用的jar完整整理

    6. **spring-aop.jar**:提供 AOP 支持,可以创建切面和通知,实现如日志记录、事务管理等功能。 7. **spring-jdbc.jar** 和 **spring-tx.jar**:数据库事务管理和 JDBC 支持,对于需要数据库操作的应用,这两个库...

    spring-boot示例项目

    aop|[aop,正则,前置通知,后置通知,环绕通知](https://github.com/smltq/spring-boot-demo/blob/master/aop/HELP.md) data-redis|[lettuce,redis,session redis,YAML配置,连接池,对象存储]...

    知识点整理1

    4. **资源加载**:Spring提供了`Resource`接口用于处理各种类型的资源,如文件、URL等。`ResourceLoader`用于获取`Resource`,而`BeanDefinition`用于存储Bean的元数据,包括其依赖和其他配置信息。`...

    最新整理Java面试题

    - **AOP**:面向切面编程,理解切点、通知、代理等概念,以及Spring AOP的实现方式。 - **Spring Boot**:快速开发特性,如自动配置、Actuator监控、Spring Data JPA等。 - **Spring Cloud**:服务治理、配置中心...

Global site tag (gtag.js) - Google Analytics