一、 AOP术语
切面(Aspect):需要实现的交叉功能
连接点(Join point):应用程序执行过程中插入切面的地点;此处可是方法的调用、异常的抛出甚至是修改的字段。
通知(Advice):通知切面的实际实现。它通知应用系统新的行为,通知在连接点插入到应用程序系统中。
切入点(point Cut):定义通知应该应用在哪些连接点。通常指定的类名和方法名,或匹配类名和方法名样式的正则表达式来制定切入点
引入(Introduction):允许为已存在类添加新方法和属性。
目标对象(Target):被通知的对象。既可是编写的类也可是添加定制行为的第三方类。
代理(Proxy):将通知应用到目标对象后创建的对象。
织入(weaving):将切面应用到目标对此那个从而创建一个心的代理对象的过程。切面是指接入点被织入到目标对象中,织入发生在目标对象生命周期的多个点上:
在指定接入点被织入到目标对象中,注入发生在目标对象生命周期的多个点上:
编译器:切面子啊目标对象编译时织入(需特殊的编译器)
类装载期:切面在目标对象被载入到jvm时织入(需要特殊的类载器,在类的载入到应用系统之前增强目标对象的字节码)
运行期:切面在用系统运行时织入(通常,AOP容器将在织入切面时动态)
二、 Sping中Aop的实现
(一) 创建通知
通知类型 |
接口 |
描述 |
Around |
import org.aopalliance.intercept.MethodInterceptor; |
拦截目标方法的前后调用 |
Before |
import org.springframework.aop.MethodBeforeAdvice; |
拦截目标方法前调用 |
After |
import org.springframework.aop.AfterReturningAdvice; |
拦截目标方法的之后调用 |
Throws |
import org.springframework.aop.ThrowsAdvice; |
目标抛出异常时调用 |
1. 前置通知
前置通知需要实现MethodBeforeAdvice接口
- import java.lang.reflect.Method;
- import org.springframework.aop.MethodBeforeAdvice;
- public class StudentAdvice implements MethodBeforeAdvice {
- @Override
- public void before(Method arg0, Object[] arg1, Object arg2)
- throws Throwable {
- System.out.println("开始学习....的前置通知!!");
- }
- }
package com.csdn.util; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class StudentAdvice implements MethodBeforeAdvice { @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { System.out.println("开始学习....的前置通知!!"); } }
注:Method 的一个参数是要实现通知的目标方法(连接点), arg1 为参数,arg2为目标对象。
目标对象
- public class StudentServiceImpl implements StudentService {
- @Override
- public void study() {
- System.out.println("调用学习的方法...");
- }
- @Override
- public void paly() {
- System.out.println("调用paly的方法....");
- }
- }
package com.csdn.service; public class StudentServiceImpl implements StudentService { @Override public void study() { System.out.println("调用学习的方法..."); } @Override public void paly() { System.out.println("调用paly的方法...."); } }
Student.xml中如下
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
- <!-- 前置通知 -->
- <bean id="studentAdvice" class="com.csdn.util.StudentAdvice" />
- <!-- 目标对象 -->
- <bean id="studentServiceImpl" class="com.csdn.service.StudentServiceImpl"/>
- <!-- 代理对象 基于接口编程 -->
- <bean id="studentProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
- <!-- 代理的接口 -->
- <property name="proxyInterfaces">
- <list>
- <value>com.csdn.service.StudentService</value>
- </list>
- </property>
- <!-- 拦截的名称 -->
- <property name="interceptorNames">
- <list>
- <!-- 不能有空格和换行 如:<value> studentAdvice </value> -->
- <value>studentAdvice</value>
- </list>
- </property>
- <!-- 目标对象 -->
- <property name="target" ref="studentServiceImpl">
- </property>
- </bean>
- </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <!-- 前置通知 --> <bean id="studentAdvice" class="com.csdn.util.StudentAdvice" /> <!-- 目标对象 --> <bean id="studentServiceImpl" class="com.csdn.service.StudentServiceImpl"/> <!-- 代理对象 基于接口编程 --> <bean id="studentProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 代理的接口 --> <property name="proxyInterfaces"> <list> <value>com.csdn.service.StudentService</value> </list> </property> <!-- 拦截的名称 --> <property name="interceptorNames"> <list> <!-- 不能有空格和换行 如:<value> studentAdvice </value> --> <value>studentAdvice</value> </list> </property> <!-- 目标对象 --> <property name="target" ref="studentServiceImpl"> </property> </bean> </beans>
注:测试接口时调用studentProxyFactoryBean如下
ApplicationContext ac = new ClassPathXmlApplicationContext(
- "applicationContext.xml");
- StudentService ss = (StudentService) ac
- .getBean("studentProxyFactoryBean");
ApplicationContext ac = new ClassPathXmlApplicationContext( "applicationContext.xml"); StudentService ss = (StudentService) ac .getBean("studentProxyFactoryBean");
1. 后置通知
后置通知需要实现AfterReturningAdvice接口如下
- import java.lang.reflect.Method;
- import org.springframework.aop.AfterReturningAdvice;
- public class StudentAfterAdvice implements AfterReturningAdvice {
- @Override
- public void afterReturning(Object returnType, Method method, Object[] arg2,Object targeType) throws Throwable {
- System.out.println("后置处理 ");
- }
- }
- 目标对象
- package com.csdn.service;
- public class StudentServiceImpl implements StudentService {
- @Override
- public void study() {
- System.out.println("调用学习的方法...");
- }
- @Override
- public void paly() {
- System.out.println("调用paly的方法....");
- }
- }
package com.csdn.util; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; public class StudentAfterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object returnType, Method method, Object[] arg2,Object targeType) throws Throwable { System.out.println("后置处理 "); } } 目标对象 package com.csdn.service; public class StudentServiceImpl implements StudentService { @Override public void study() { System.out.println("调用学习的方法..."); } @Override public void paly() { System.out.println("调用paly的方法...."); } }
- 环绕通知实现MethodInterceptor接口:
- 实现的方法为
- package com.csdn.util;
- import org.aopalliance.intercept.MethodInterceptor;
- import org.aopalliance.intercept.MethodInvocation;
- public class StudentAround implements MethodInterceptor {
- @Override
- public Object invoke(MethodInvocation invocation) throws Throwable {
- System.out.println("前");
- Object obj=invocation.proceed();//调用目标方法
- System.out.println("后");
- return obj;
- }
- }
- 与前面的两种区别
- MethodInterceptor能控制方法是否真的被调用。通过调用MethodInvocation的Proceed()方法来调用目标方法。
- Method能控制返回的对象。
- 4. 异常通知
- 异常通知需要是想的接口是ThrowsAdvice
- package com.csdn.util;
- import java.lang.reflect.Method;
- import org.springframework.aop.ThrowsAdvice;
- public class StudentException implements ThrowsAdvice {
- public void afterThrowing(Method method, Object[] args, Object target,
- Exception ex) {
- System.out.println("方法的名称:" + method + "方法的参数" + args.length + "目标对象:"
- + target.getClass().getName() + "异常" + ex.getMessage());
- }
- }
- Xml中如下
- <!-- 异常对象的获取 -->
- <bean id="studentException" class="com.csdn.util.StudentException" />
- <!-- 目标对象 -->
- <bean id="studentServiceImpl" class="com.csdn.service.StudentServiceImpl"/>
- <!-- 代理对象 基于接口编程 -->
- <bean id="studentProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
- <!-- 代理的接口 -->
- <property name="proxyInterfaces">
- <list>
- <value>com.csdn.service.StudentService</value>
- </list>
- </property>
- <!-- 拦截的名称 -->
- <property name="interceptorNames">
- <list>
- <!-- 不能有空格和换行 如:<value> studentAdvice </value> -->
- <value>studentException</value>
- </list>
- </property>
- <!-- 目标对象 -->
- <property name="target" ref="studentServiceImpl">
- </property>
- </bean>
3. 环绕通知 环绕通知实现MethodInterceptor接口: 实现的方法为 package com.csdn.util; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class StudentAround implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("前"); Object obj=invocation.proceed();//调用目标方法 System.out.println("后"); return obj; } } 与前面的两种区别 MethodInterceptor能控制方法是否真的被调用。通过调用MethodInvocation的Proceed()方法来调用目标方法。 Method能控制返回的对象。 4. 异常通知 异常通知需要是想的接口是ThrowsAdvice package com.csdn.util; import java.lang.reflect.Method; import org.springframework.aop.ThrowsAdvice; public class StudentException implements ThrowsAdvice { public void afterThrowing(Method method, Object[] args, Object target, Exception ex) { System.out.println("方法的名称:" + method + "方法的参数" + args.length + "目标对象:" + target.getClass().getName() + "异常" + ex.getMessage()); } } Xml中如下 <!-- 异常对象的获取 --> <bean id="studentException" class="com.csdn.util.StudentException" /> <!-- 目标对象 --> <bean id="studentServiceImpl" class="com.csdn.service.StudentServiceImpl"/> <!-- 代理对象 基于接口编程 --> <bean id="studentProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 代理的接口 --> <property name="proxyInterfaces"> <list> <value>com.csdn.service.StudentService</value> </list> </property> <!-- 拦截的名称 --> <property name="interceptorNames"> <list> <!-- 不能有空格和换行 如:<value> studentAdvice </value> --> <value>studentException</value> </list> </property> <!-- 目标对象 --> <property name="target" ref="studentServiceImpl"> </property> </bean>
- <!-- 后置通知 -->
- <bean id="studentAfterAdvice"class="com.csdn.util.StudentAfterAdvice"/>
- <!-- 目标对象 -->
- <bean id="studentServiceImpl" class="com.csdn.service.StudentServiceImpl"/>
- <!-- 代理对象 基于接口编程 -->
- <bean id="studentProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
- <!-- 代理的接口 -->
- <property name="proxyInterfaces">
- <list>
- <value>com.csdn.service.StudentService</value>
- </list>
- </property>
- <!-- 拦截的名称 -->
- <property name="interceptorNames">
- <list>
- <!-- 不能有空格和换行 如:<value> studentAdvice </value> -->
- <value>studentAfterAdvice</value>
- </list>
- </property>
- <!-- 目标对象 -->
- <property name="target" ref="studentServiceImpl">
- </property>
- </bean>
- 注:测试接口时调用studentProxyFactoryBean如下
- ApplicationContext ac = new ClassPathXmlApplicationContext(
- "applicationContext.xml");
- StudentService ss = (StudentService) ac
- .getBean("studentProxyFactoryBean");
Student.xml中如下 <!-- 后置通知 --> <bean id="studentAfterAdvice"class="com.csdn.util.StudentAfterAdvice"/> <!-- 目标对象 --> <bean id="studentServiceImpl" class="com.csdn.service.StudentServiceImpl"/> <!-- 代理对象 基于接口编程 --> <bean id="studentProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 代理的接口 --> <property name="proxyInterfaces"> <list> <value>com.csdn.service.StudentService</value> </list> </property> <!-- 拦截的名称 --> <property name="interceptorNames"> <list> <!-- 不能有空格和换行 如:<value> studentAdvice </value> --> <value>studentAfterAdvice</value> </list> </property> <!-- 目标对象 --> <property name="target" ref="studentServiceImpl"> </property> </bean> 注:测试接口时调用studentProxyFactoryBean如下 ApplicationContext ac = new ClassPathXmlApplicationContext( "applicationContext.xml"); StudentService ss = (StudentService) ac .getBean("studentProxyFactoryBean");