AOP(Aspect Oriented Programming) 面向切面编程,是对一类或是所有对象编程。 核心:在不增加、改变代码的基础上,增加新的功能。 aop编程,在框架开发中,应用很多;在实际开发中,用的不是很多。 编程阶段:面向机器(汇编)->面向过程->面向对象->面向切面
spring的运行时通知对象; spring在运行期间创建代理,不需要特殊的编译器。 spring有两种代理方式: 1 若目标对象实现了若干接口 spring使用JDK的java.lang.reflect.Proxy类代理。该类让spring动态产生一个新类,它实现了所需的接口,织入通知,并且代理对目标对象的所有请求。 2 若目标没有实现任何接口 spring使用CGLIB库生成目标对象的子类。使用该方式时需要注意。 - 对接口创建代理优先对类创建代理,因为会产生更加松耦合的系统;对类代理是让遗留系统或无法实现接口的第三方类库同样可以得到通知。这种方式应该是备用方案。 - 标记为final的方法不能够被通知。spring是为目标类产生子类。任何需要被通知的方法都被复写,将通知织入。final方法是不允许重写的。 spring实现了aop联盟接口。 **spring只支持方法连接点;不提供属性连接点。**spring的观点是属性拦截破坏了封装。面向对象的概念是对象自己处理工作,其他对象只能通过方法调用得到的结果。
开发步骤: - 定义接口 - 编写对象(被代理对象==目标对象) - 编写通知(前置通知- - -目标方法调用前调用) - 在beans.xml文件中配置 - 配置被代理对象 - 配置通知 - 配置代理对象,是ProxyFactoryBean的对象实例 - - 代理接口集proxyInterfaces - - 织入通知interceptorNames - - 配置被代理对象target
---------------------------- 通知类型 接口 描述 ---------------------------- Around MethodInterceptor 拦截对目标方法调用 Before MethodBeforeAdvice 在目标方法调用前调用 After AfterReturningAdvice 在目标方法调用后调用 Throws ThrowsAdvice 当目标方法抛出异常时调用 -----------------------------
该通知能够控制目标方法是否真的被调用; 同时也可以控制返回的对象。
public class MyMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation arg0) throws Throwable { // TODO Auto-generated method stub System.out.println("调用前...."); Object obj = arg0.proceed(); // 调用的方法 System.out.println("调用后...."); return obj; } }该接口是标识性接口,没有任何方法,但实现该接口的类必须要有如下形式的方法:
public void afterThrowing(Exception e); public void afterThrowing(Method method, Object[] os, Object target, Exception e);第一个方法只接受一个参数:需要抛出的异常。 第二个方法接受异常、被调用的方法、参数以及目标对象
public class MyThrowsAdvice implements ThrowsAdvice { public void afterThrowing(Exception e){ System.out.println("000出大事了 " + e.getMessage()); } public void afterThrowing(Method method, Object[] os, Object target, Exception e){ System.out.println(method+ " 111出大事了 " + e.getMessage()); } }以前定义的通知类型是在目标对象的方法被调用的周围织入。引入通知给目标对象添加新的方法和属性。 只需要在xml配置文件中进行配置:
<?xml version="1.0" encoding="utf-8"?> <beans> <!-- 配置被代理的对象 --> <bean id="test1Servece" class="com.test.aop.Test1Service"> <property name="name" value="jiaozl"></property> </bean> <!-- 配置前置通知 --> <bean id="myMethodBeforeAdvice" class="com.test.aop.MyMethodBeforeAdvice"/> <!-- 配置后置通知 --> <bean id="myAfterReturningAdvice" class="com.test.aop.MyAfterReturningAdvice"/> <bean id="myMethodInterceptor" class="com.test.aop.MyMethodInterceptor"/> <bean id="myThrowsAdvice" class="com.test.aop.MyThrowsAdvice"/> <!-- 定义前置通知的切入点 --> <bean id="myMethodBeforeAdviceFilter" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="advice" ref="myMethodBeforeAdvice"/> <property name="mappedNames"> <list> <!-- 只对sayBye方法通知 --> <value>sayBye</value> </list> </property> </bean> <!-- 配置代理对象 ProxyFactoryBean implements TestServiceInter { public void sayHello() {}; } --> <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 代理接口集 --> <property name="proxyInterfaces"> <list> <value>com.test.aop.TestServiceInter</value> <value>com.test.aop.TestServiceInter2</value> </list> </property> <!-- 把通知织入到代理对象 --> <property name="interceptorNames"> <list> <!-- 使用自定义切入点来控制前置通知 --> <value>myMethodBeforeAdviceFilter</value> <value>myAfterReturningAdvice</value> <value>myMethodInterceptor</value> <value>myThrowsAdvice</value> </list> </property> <!-- 配置被代理对象,可以指定 --> <property name="target" ref="test1Servece"/> </bean> </beans>