前面已经学过了bean的相关知识,对bean的配置方法也有了一定的了解。下面来学习Spring中一个重要的知识点AOP编程,这些知识点都是根据韩顺平老师的视频总结而来,虽然简单,但是作为入门了解还是不错的。不过想要真正的应用到项目中,还需要进行深一步的学习。
- AOP的概念
AOP(aspect oriented programming)面向切面编程,是对所有对象或是一类对象编程,核心是在不增加代码的基础上,还能增加功能。他所应用到的场景一般是将交叉功能(事务、日志)提取出来。
2、AOP术语
1、切面:要实现的交叉功能,是系统模块化的一个切面或者领域(如日志记录等)
2、连接点:应用程序执行过程中插入切面的地点,可以是方法调用,异常抛出,或者要修改的字段。
3、通知:切面的实际实现,他通知系统新的行为。如在日志通知包含了实现日志功能的代码,向日志文件写日志。通知在连接点插入到应用系统中。
4、切入点:定义了通知应该应用在哪些连接点,通知可以应用到AOP框架支持的任何连接点。
5、引入:为类添加新的方法和属性
6、目标对象:被通知的对象,既可以是你编写的类,也可以是第三方的类
7、代理:将通知应用到目标对象后创建的对象,应用系统的其他部分不用为了支持代理对象而改变
8、织入:将切面应用到目标对象从而创建一个新的代理对象的过程。织入发生在目标对象生命周期的多个点上
编译器:切面在目标对象编译时织入,这需要一个特殊的编译器
类装载器:切面在目标对象那个被载入JVM是织入,这需要一个特殊的类载入器
运行期:切面在应用系统运行时织入
3、配置步骤
步骤:
1、定义接口
2、编写对象(被代理对象=目标对象)
3、编写通知
4、bean.xml文件配置
1、配置被代理对象
2、配置通知
3、配置代理对象(是proxyFactoryBean实例)
a、配置被代理对象
b、配置代理接口集
c、把通知织入代理对象
下面我们来举个例子,需求就是在调用UserBean 的sayHello()前利用前置通知完成日志的书写,利用环绕通知将sayHello方法包裹起来(然而现在并不能了解环绕通知的具体应用场景是什么),调用完sayHello方法后,最后用后置通知释放资源。
首先来看一下框架图:
- 定义接口:
package rogue.aop; public interface TestSeverInter { public void sayHello(); } package rogue.aop; public interface TestSeverInter2 { public void sayBye(); }
2.编写目标对象
package rogue.aop; public class SeverTest1 implements TestSeverInter,TestSeverInter2 { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void sayHello() { System.out.println("Hello"+name); } @Override public void sayBye() { System.out.println("Bye"+name); } }
3、编写通知.package rogue.aop; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class MyMethodBeforeAdvice implements MethodBeforeAdvice { @Override /** * method:被调用的方法的名字 * args:传递的参数 * target:目标对象(就是被调用的对象) * */ public void before(Method method, Object[] args, Object target) throws Throwable { // TODO Auto-generated method stub System.out.println("前置通知-通知日志..."+method.getName()); } }
package rogue.aop; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class MyMethodSurroundAdvice implements MethodInterceptor { @Override public Object invoke(MethodInvocation arg0) throws Throwable { // TODO Auto-generated method stub System.out.println("调用环绕通知前。。"); arg0.proceed(); System.out.println("调用环绕通知后。。"); return null; } }
package rogue.aop; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; public class MyMethodAfterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { // TODO Auto-generated method stub System.out.println("关闭资源。。。"); } }
4、bean.xml的配置<?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="SeverTest1" class="rogue.aop.SeverTest1"> <property name="name" value="大帽子" /> </bean> <!--配置通知--> <!-- 配置前置通知 --> <bean id="MyMethodBeforeAdvice" class="rogue.aop.MyMethodBeforeAdvice" /> <!-- 配置后置通知 --> <bean id="MyMethodAfterAdvice" class="rogue.aop.MyMethodAfterAdvice" /> <!-- 配置环绕通知 --> <bean id="MyMethodSurroundAdvice" class="rogue.aop.MyMethodSurroundAdvice" /> <!-- 配置代理对象(也就是将被代理对象,接口和通知整合起来,配置在一起) --> <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 第一步:将被代理对象织入到代理对象中 (name一定要是target)--> <property name="target" ref="SeverTest1"></property> <!-- 第二步:将代理接口集织入到代理对象中 (name一定要是proxyInterfaces)--> <property name="proxyInterfaces"> <list> <value>rogue.aop.TestSeverInter</value><!-- 这里应该是全限定名 --> <value>rogue.aop.TestSeverInter2</value> </list> </property> <!-- 第三步:把通知织入到代理对象(name一定要是interceptorNames) --> <property name="interceptorNames"> <list> <!-- 相当于把MyMethodBeforeAdvice前置通知和代理对象关联,也可以把通知看作拦截器 --> <value>MyMethodBeforeAdvice</value> <value>MyMethodAfterAdvice</value> <value>MyMethodSurroundAdvice</value> </list> </property> </bean> </beans>
测试程序package rogue.aop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class app { /** * @param args */ public static void main(String[] args) { ApplicationContext aContext = new ClassPathXmlApplicationContext("rogue/aop/aop.xml"); //在这里我们应该取proxyFactoryBean,因为在这里面有我们织入的通知,执行完通知后再执行正常的代码 TestSeverInter tS = (TestSeverInter) aContext.getBean("proxyFactoryBean"); tS.sayHello(); System.out.println("**********************************"); ((TestSeverInter2)tS).sayBye(); } }
结果截图: