`

Spring AOP 简单理解

 
阅读更多

AOP技术即(面向切面编程)技术是在面向对象编程基础上的发展,AOP技术是对所有对象或一类对象编程。核心是在不增加代码的基础上,还增加了新的功能。AOP编程在开发框架本身用的比较多,而实际项目中,用的比较少。它是将分散在各个业务逻辑代码中的相同代码抽取出来形成一个独立的模块。

1、定义AOP术语

(1)切面(aspect):要实现的交叉功能,是系统模块化的一个切面或领域。

(2)通知(advice):切面的具体实现,包含五类通知。

(3)连接点(jointpoint):应用程序执行过程中插入切面的地点。

(4)切点(cutpoint):定义通知应该应用哪些连接点。

(5)引入(introduction):为类添加新方法和属性。

(6)目标对象(target):通知逻辑的织入目标类。

(7)代理(proxy):将通知应用到目标对象后创建的对象,应用系统的其他部分不用为了支持代理对象而改变

(8)织入(weaving):将切面应用到目标对象从而创建一个新代理对象的过程。

 

2、AOP原理和实例

(1)基础接口和类的实现:

package com.jasson.aop;

public interface TestServiceInter1 {

	public void sayHello();
}


package com.jasson.aop;

public interface TestServiceInter2 {

	public void sayBye();
	
	public void sayHi();
}

 (2)实现类如下:

package com.jasson.aop;

public class TestService implements TestServiceInter1,TestServiceInter2 {

	public void sayHello() {
		System.out.println("sayHello() method ");
	}

	public void sayBye() {
		System.out.println("sayBye() method");
	}
	
	public void sayHi() {
		System.out.println("sayHi() method");
	}
}

 

(1)前置通知:要求在每个方法调用前进行日志记录,则用的前置通知,定义如下:

package com.jasson.aop;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class MyMethodBeforeAdvice implements MethodBeforeAdvice {

	/**
	 * method: 方法名
	 * args: 输入参数
	 * target: 目标对象
	 */
	public void before(Method method, Object[] args, Object target)
			throws Throwable {
		System.out.println("前置通知调用 记录日志..."+method.getName());
	}
}

 

配置文件如下:

 

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns:context="http://www.springframework.org/schema/context"
		xmlns:tx="http://www.springframework.org/schema/tx"
		xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" 
				>
<!-- 配置被代理的对象,即目标对象 -->
<bean id="testService" class="com.jasson.aop.TestService" />
<!-- 配置前置通知 -->
<bean id="myMethodBeforeAdvice" class="com.jasson.aop.MyMethodBeforeAdvice" />
<!-- 配置代理对象 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
	<!-- 代理接口集 -->
	<property name="proxyInterfaces">
		<list>
			<value>com.jasson.aop.TestServiceInter1</value>
			<value>com.jasson.aop.TestServiceInter2</value>
		</list>
	</property>
	<!-- 把通知织入到代理对象  -->
	<property name="interceptorNames">
		<!-- 相当于包MyMethodBeforeAdvice前置通知和代理对象关联,我们也
		可以把通知看出拦截器,struts2核心拦截器 -->
		<list>
			<value>myMethodBeforeAdvice</value>
		</list>
	</property>
	<!-- 配置被代理对象,即目标对象 -->
	<property name="target" ref="testService"/>
</bean>
</beans>

 

package com.jasson.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App1 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ApplicationContext ac=new ClassPathXmlApplicationContext("com/jasson/aop/beans.xml");
		TestServiceInter1 ts=(TestServiceInter1) ac.getBean("proxyFactoryBean");
		ts.sayHello();
		System.out.println("*******************************************");
		((TestServiceInter2)ts).sayBye();
		System.out.println("*******************************************");
		((TestServiceInter2)ts).sayHi();
	}

}

 

 执行结果如下:

31-May-2012 18:19:53 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@c8f6f8: defining beans [testService,myMethodBeforeAdvice,myAfterReturningAdvice,myMethodInterceptor,myThrowsAdvice,proxyFactoryBean]; root of factory hierarchy
前置通知调用 记录日志...sayHello
sayHello() method 
*******************************************
前置通知调用 记录日志...sayBye
sayBye() method
*******************************************
前置通知调用 记录日志...sayHi
sayHi() method

 

(2)后置通知:要求在调用每个方法后执行的功能,例如在调用每个方法后关闭资源

 

package com.jasson.aop;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class MyAfterReturningAdvice implements AfterReturningAdvice {

	@Override
	public void afterReturning(Object returnValue, Method method, Object[] arg,
			Object target) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("后置通知调用,关闭资源..."+method.getName());
	}
}

 bean 配置如下:

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns:context="http://www.springframework.org/schema/context"
		xmlns:tx="http://www.springframework.org/schema/tx"
		xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" 
				>
<!-- 配置被代理的对象,即目标对象 -->
<bean id="testService" class="com.jasson.aop.TestService" />
<!-- 配置前置通知 -->
<bean id="myMethodBeforeAdvice" class="com.jasson.aop.MyMethodBeforeAdvice" />
<!-- 配置后置通知 -->
<bean id="myAfterReturningAdvice" class="com.jasson.aop.MyAfterReturningAdvice" />
<!-- 配置代理对象 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
	<!-- 代理接口集 -->
	<property name="proxyInterfaces">
		<list>
			<value>com.jasson.aop.TestServiceInter1</value>
			<value>com.jasson.aop.TestServiceInter2</value>
		</list>
	</property>
	<!-- 把通知织入到代理对象  -->
	<property name="interceptorNames">
		<!-- 相当于包MyMethodBeforeAdvice前置通知和代理对象关联,我们也
		可以把通知看出拦截器,struts2核心拦截器 -->
		<list>
			<value>myMethodBeforeAdvice</value>
			<value>myAfterReturningAdvice</value>
		</list>
	</property>
	<!-- 配置被代理对象,即目标对象 -->
	<property name="target" ref="testService"/>
</bean>
</beans>

 

执行结果如下:

 

 

INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@122cdb6: defining beans [testService,myMethodBeforeAdvice,myAfterReturningAdvice,myMethodInterceptor,myThrowsAdvice,proxyFactoryBean]; root of factory hierarchy
前置通知调用 记录日志...sayHello
sayHello() method 
后置通知调用,关闭资源...sayHello
*******************************************
前置通知调用 记录日志...sayBye
sayBye() method
后置通知调用,关闭资源...sayBye
*******************************************
前置通知调用 记录日志...sayHi
sayHi() method
后置通知调用,关闭资源...sayHi

 

(3)环绕通知:指在某个具体的方法中,添加相应的操作

package com.jasson.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MyMethodInterceptor implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation arg) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("环绕通知调用方法前");
		Object obj = arg.proceed();
		System.out.println("环绕通知调用方法后");
		return obj;
	}
}

 

配置文件如下:

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns:context="http://www.springframework.org/schema/context"
		xmlns:tx="http://www.springframework.org/schema/tx"
		xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" 
				>
<!-- 配置被代理的对象,即目标对象 -->
<bean id="testService" class="com.jasson.aop.TestService" />
<!-- 配置前置通知 -->
<bean id="myMethodBeforeAdvice" class="com.jasson.aop.MyMethodBeforeAdvice" />
<!-- 配置后置通知 -->
<bean id="myAfterReturningAdvice" class="com.jasson.aop.MyAfterReturningAdvice" />
<!-- 配置环绕通知 -->
<bean id="myMethodInterceptor" class="com.jasson.aop.MyMethodInterceptor" />
<!-- 配置代理对象 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
	<!-- 代理接口集 -->
	<property name="proxyInterfaces">
		<list>
			<value>com.jasson.aop.TestServiceInter1</value>
			<value>com.jasson.aop.TestServiceInter2</value>
		</list>
	</property>
	<!-- 把通知织入到代理对象  -->
	<property name="interceptorNames">
		<!-- 相当于包MyMethodBeforeAdvice前置通知和代理对象关联,我们也
		可以把通知看出拦截器,struts2核心拦截器 -->
		<list>
			<value>myMethodBeforeAdvice</value>
			<value>myAfterReturningAdvice</value>
			<value>myMethodInterceptor</value>
		</list>
	</property>
	<!-- 配置被代理对象,即目标对象 -->
	<property name="target" ref="testService"/>
</bean>
</beans>

 执行结果如下:

INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1ce2dd4: defining beans [testService,myMethodBeforeAdvice,myAfterReturningAdvice,myMethodInterceptor,proxyFactoryBean]; root of factory hierarchy
前置通知调用 记录日志...sayHello
环绕通知调用方法前
sayHello() method 
环绕通知调用方法后
后置通知调用,关闭资源...sayHello
*******************************************
前置通知调用 记录日志...sayBye
环绕通知调用方法前
sayBye() method
环绕通知调用方法后
后置通知调用,关闭资源...sayBye
*******************************************
前置通知调用 记录日志...sayHi
环绕通知调用方法前
sayHi() method
环绕通知调用方法后
后置通知调用,关闭资源...sayHi

 (4)异常通知:当发生异常时,要执行的通知

package com.jasson.aop;

import java.lang.reflect.Method;

import org.springframework.aop.ThrowsAdvice;

public class MyThrowsAdvice implements ThrowsAdvice {

	public void afterThrowing(Method method, Object[] os, Object target,
			Exception exception) {

		System.out.println("异常通知产生异常,进行处理" + exception.getMessage());
	}
}

 

 

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns:context="http://www.springframework.org/schema/context"
		xmlns:tx="http://www.springframework.org/schema/tx"
		xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" 
				>
<!-- 配置被代理的对象,即目标对象 -->
<bean id="testService" class="com.jasson.aop.TestService" />
<!-- 配置前置通知 -->
<bean id="myMethodBeforeAdvice" class="com.jasson.aop.MyMethodBeforeAdvice" />
<!-- 配置后置通知 -->
<bean id="myAfterReturningAdvice" class="com.jasson.aop.MyAfterReturningAdvice" />
<!-- 配置环绕通知 -->
<bean id="myMethodInterceptor" class="com.jasson.aop.MyMethodInterceptor" />
<!-- 配置异常通知 -->
<bean id="myThrowsAdvice" class="com.jasson.aop.MyThrowsAdvice" />
<!-- 配置代理对象 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
	<!-- 代理接口集 -->
	<property name="proxyInterfaces">
		<list>
			<value>com.jasson.aop.TestServiceInter1</value>
			<value>com.jasson.aop.TestServiceInter2</value>
		</list>
	</property>
	<!-- 把通知织入到代理对象  -->
	<property name="interceptorNames">
		<!-- 相当于包MyMethodBeforeAdvice前置通知和代理对象关联,我们也
		可以把通知看出拦截器,struts2核心拦截器 -->
		<list>
			<value>myMethodBeforeAdvice</value>
			<value>myAfterReturningAdvice</value>
			<value>myMethodInterceptor</value>
			<value>myThrowsAdvice</value>
		</list>
	</property>
	<!-- 配置被代理对象,即目标对象 -->
	<property name="target" ref="testService"/>
</bean>

 

package com.jasson.aop;

public class TestService implements TestServiceInter1,TestServiceInter2 {

	public void sayHello() {
		System.out.println("sayHello() method ");
	}

	public void sayBye() {
		System.out.println("sayBye() method");
	}
	
	public void sayHi() {
		int a =10/0;
		System.out.println("sayHi() method");
	}
}

 

执行结果如下:

INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1ce2dd4: defining beans [testService,myMethodBeforeAdvice,myAfterReturningAdvice,myMethodInterceptor,myThrowsAdvice,proxyFactoryBean]; root of factory hierarchy
前置通知调用 记录日志...sayHello
环绕通知调用方法前
sayHello() method 
环绕通知调用方法后
后置通知调用,关闭资源...sayHello
*******************************************
前置通知调用 记录日志...sayBye
环绕通知调用方法前
sayBye() method
环绕通知调用方法后
后置通知调用,关闭资源...sayBye
*******************************************
前置通知调用 记录日志...sayHi
环绕通知调用方法前
异常通知产生异常,进行处理/ by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero

 

(5)上面的通知都是针对每个方法的,如果只是对单个或者一类的方法进行相应处理的时,可采用名字或者正则表达式的方式进行处理

配置如下:

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns:context="http://www.springframework.org/schema/context"
		xmlns:tx="http://www.springframework.org/schema/tx"
		xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" 
				>
<!-- 配置被代理的对象,即目标对象 -->
<bean id="testService" class="com.jasson.aop.TestService" />
<!-- 配置前置通知 -->
<bean id="myMethodBeforeAdvice" class="com.jasson.aop.MyMethodBeforeAdvice" />
<!-- 配置后置通知 -->
<bean id="myAfterReturningAdvice" class="com.jasson.aop.MyAfterReturningAdvice" />
<!-- 配置环绕通知 -->
<bean id="myMethodInterceptor" class="com.jasson.aop.MyMethodInterceptor" />
<!-- 配置异常通知 -->
<bean id="myThrowsAdvice" class="com.jasson.aop.MyThrowsAdvice" />

<!-- 通知与正则表达式切入点一起配置 -->  
<!-- Advisor等于切入点加通知,所有say开头的方法添加前置通知 -->  
<bean id="regexpPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">  
    <property name="advice" ref="myMethodBeforeAdvice"/>  
    <property name="patterns">  
        <list>  
            <value>.*say.*</value>  
        </list>  
    </property>  
</bean>  

<!-- 方法名匹配切入点配置器:只对 sayHello方法添加环绕通知-->  
<bean id="namePointcutAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">  
    <property name="advice" ref="myMethodInterceptor"/>  
    <property name="mappedNames">  
        <list>  
            <value>sayHello</value>  
        </list>  
    </property>  
</bean> 

<!-- 配置代理对象 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
	<!-- 代理接口集 -->
	<property name="proxyInterfaces">
		<list>
			<value>com.jasson.aop.TestServiceInter1</value>
			<value>com.jasson.aop.TestServiceInter2</value>
		</list>
	</property>
	<!-- 把通知织入到代理对象  -->
	<property name="interceptorNames">
		<!-- 相当于包MyMethodBeforeAdvice前置通知和代理对象关联,我们也
		可以把通知看出拦截器,struts2核心拦截器 -->
		<list>
			<value>namePointcutAdvisor</value>
			<value>myAfterReturningAdvice</value>
			<value>regexpPointcutAdvisor</value>
			<value>myThrowsAdvice</value>
		</list>
	</property>
	<!-- 配置被代理对象,即目标对象 -->
	<property name="target" ref="testService"/>
</bean>
</beans>

 

执行结果如下:

INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1ef9157: defining beans [testService,myMethodBeforeAdvice,myAfterReturningAdvice,myMethodInterceptor,myThrowsAdvice,regexpPointcutAdvisor,namePointcutAdvisor,proxyFactoryBean]; root of factory hierarchy
环绕通知调用方法前
前置通知调用 记录日志...sayHello
sayHello() method 
后置通知调用,关闭资源...sayHello
环绕通知调用方法后
*******************************************
前置通知调用 记录日志...sayBye
sayBye() method
后置通知调用,关闭资源...sayBye
*******************************************
前置通知调用 记录日志...sayHi
异常通知产生异常,进行处理/ by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero

 

 

 

分享到:
评论

相关推荐

    SpringAop的简单理解.pdf

    SpringAop的简单理解.pdf

    spring aop简单示例.rar

    aop的原理基于java动态代理模式,本资源是spring的aop运用简单示例,用于帮助初学者理解和运用aop技术

    最简单的SpringAOP入门案例

    最简单的SpringAOP入门案例,对于配置文件有详细的解释,适合初学者去理解AOP编程

    SpringAOP入门

    本文主要是介绍SpringAOP的相关知识,在本文里面我能介绍了SpringAOP的实现机理,在实现过程中所用到的相关技术,最后,通过一个简单的实例来对SpringAOP进行实现,进而加读者对SpringAOP的理解,以达到熟练运用的...

    spring aop 实例

    spring aop部分的简单实例,容易理解

    spring ioc aop基础理论实践笔记

    1,spring是一个开源的免费的框架(容器)。 2,spring是一个轻量级的,非入侵式的框架。 ​ 非入侵式:就是项目引入了这个框架之后,...总结:spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。

    Spring4—AOP编程

    aop写一个简单的计算器:(1)日志功能:在程序执行期间追踪正在发生的活动(打印出调用的方法,以及参数的参数值);...利用简单的实例来理解spring的aop编程,以aspectJ为例,理解环绕通知的真正含义。

    《Spring AOP遇上循环依赖》Spring源码期末考压轴题,真懂的人不多!

    再细问:如果循环依赖的时候,所有类又都需要Spring AOP自动代理,那Spring如何提前曝光?曝光的是原始bean还是代理后的bean? 这些问题算是Spring源码的压轴题了,如果这些问题都弄明白,恭喜你顺利结业Spring源码...

    aop简单实例

    从这几个小例子,理解aop原理,以及Spring AOP的实现原理

    Around_AOP_Spring.zip_aop

    AOP是Spring两大核心技术之一,该代码实现了AOP中环绕式切面的功能,通过一个简单的例子,很好的理解环绕式切面

    spring的aop小程序

    aop的@Before、@After等标签简单用法小程序,根据网上的例子写的,包含了用到的jar包,希望能帮到初学者理解这些标签的用法

    简单理解Spring之IOC和AOP及代码示例

    主要介绍了简单理解Spring之IOC和AOP及代码示例,具有一定参考价值,需要的朋友可以了解下。

    spring的aop标签使用小程序

    aop的@Before、@After等标签简单用法小程序,根据网上的例子写的,包含了用到的jar包,希望能帮到初学者理解这些标签的用法

    注解+AOP优雅的实现java项目的接口参数校验(含源码)

    基于Spring boot + maven,以注解+AOP方式实现的java后端项目接口参数校验框架。迄今为止使用最简单、最容易理解的参数校验方案。博客地址:https://blog.csdn.net/weixin_42686388/article/details/104009771

    深入理解Spring声明式事务:源码分析与应用实践

    Spring框架的声明式事务管理是Java开发中的核心特性,它为高效且可靠的数据操作提供了强大支持。...深入理解Spring声明式事务的工作原理,不仅能帮助开发者更高效地使用Spring框架,也是提升Java企业级开发能力的关键。

    Spring的简单应运

    简单的一个spring的实现更好帮助我们来理解Aop的代理模式

    java AOP aspectjrt-1.8.14 AOP核心大集合

    spring-aop:AOP核心功能,例如代理工厂等等aspectjweaver:简单理解,支持切入点表达式等等aspectjrt:简单理解,支持aop相关注解等等

    springboot AOP使用实例源码

    在Springboot上使用AOP的简单实例源码,可以结合本人的文章一起学习理解 https://blog.csdn.net/vincent_yuan89/article/details/85128009

    掌握Spring设计模式:Java工程师必备指南

    作为一个资深Java工程师,我发现《Spring 设计模式总结》PDF非常精彩,它深入剖析了Spring框架...这些模式共同构成了Spring框架的设计骨架,对于任何Java工程师来说,理解和掌握这些模式是提升自己架构设计能力的关键。

Global site tag (gtag.js) - Google Analytics