一 AOP 相关概念
Joinpoint(连接点): 所谓连接点是指那些被拦截到的点. 在 spring 中, 这些点指的是方法, 因为 spring 只支持方法类型的连接点.
Pointcut(切入点): 所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义.
Advice(通知 / 增强): 所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知. 通知分为前置通知, 后置通知, 异常通知, 最终通知, 环绕通知(切面要完成的功能)
Introduction(引介): 引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field.
Target(目标对象): 代理的目标对象
Weaving(织入): 是指把增强应用到目标对象来创建新的代理对象的过程.
spring 采用动态代理织入, 而 AspectJ 采用编译期织入和类装在期织入
Proxy(代理): 一个类被 AOP 织入增强后, 就产生一个结果代理类
Aspect(切面): 是切入点和通知 (引介) 的结合
二, AOP 的底层实现
AOP 底层使用的代理技术 : JDK 动态代理 和 CGlib 的动态代理.
AOP 开发规范 : AOP 联盟为通知 Advice 定义了 org.aopalliance.aop.Interface.Advice. Spring AOP 实现 AOP 联盟定义 规范
传统 Spring AOP 提供 五类 Advice
a 前置通知(代码增强) org.springframework.aop.MethodBeforeAdvice 在目标方法执行前实施增强
b 后置通知 org.springframework.aop.AfterReturningAdvice 在目标方法执行后实施增强
c 环绕通知 org.aopalliance.intercept.MethodInterceptor 在目标方法执行前后实施增强
d 异常抛出通知 org.springframework.aop.ThrowsAdvice 在方法抛出异常后实施增强
e 引介通知 org.springframework.aop.IntroductionInterceptor 在目标类中添加一些新的方法和属性
2, Spring 的切面 Advisor
Advisor 就是对 PointCut 应用 Advice (通常所说 Advisor 指只有一个 Point 和 一个 Advice )
通过配置实现增强
采用 jdk 动态代理实现, 有一个接口 UserService, 实现类 UserImpl, 不配置切点
UserService 接口
- package dflx;
- public interface UserService {
- public void add();
- public void serach();
- }
实现类 UserImpl
- public class UserImpl implements UserService {
- @Override
- public void add() {
- System.out.println("add user");
- }
- @Override
- public void serach() {
- System.out.println("search user");
- }
- }
AOP 的配置如下
- <?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.xsd">
- <!-- 不带切点和切面 -->
- <!-- 被代理对象 -->
- <bean id="user" class="dflx.UserImpl"></bean>
- <!-- 增强 -->
- <bean id="mybeforeadvice" class="dflx.MethodBeforeTest"></bean>
- <bean id="userDAOProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <!-- 目标 -->
- <property name="target" ref="user"></property>
- <!-- 针对接口代理 -->
- <property name="proxyInterfaces" value="dflx.UserService"></property>
- <property name="interceptorNames" value="mybeforeadvice"></property>
- </bean>
- </beans>
image.png
通过如下方法测试
- @Test
- public void test() {
- ApplicationContext app=new ClassPathXmlApplicationContext("app.xml");
- UserService user=(UserService) app.getBean("userDAOProxy");
- user.add();
- user.serach();
- }
结果如下
前置增强 -----------
add user
前置增强 -----------
search user
image.png
采用 Cglib 的动态代理, 有切点和切面.
有一个 OrderDAO 类, Advice 通知增强类 MyMethodInterceptor
- public class OrderDAO {
- public void add() {
- System.out.println("添加订单");
- }
- public void delete() {
- System.out.println("删除订单");
- }
- public void search() {
- System.out.println("查询订单");
- }
- }
Advice 通知增强类
- import org.aopalliance.intercept.MethodInterceptor;
- import org.aopalliance.intercept.MethodInvocation;
- public class MyMethodInterceptor implements MethodInterceptor {
- @Override
- public Object invoke(MethodInvocation arg) throws Throwable {
- System.out.println("环绕前增强");
- Object resultObject=arg.proceed(); // 目标方法执行
- System.out.println("环绕后增强");
- return resultObject;
- }
- }
AOP 的配置如下
- <?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.xsd">
- <!-- 带有切点的切面 -->
- <!-- 被代理的对象 -->
- <bean id="orderDAO" class="day0916.OrderDAO"></bean>
- <!-- 增强 -->
- <bean id="mymethodinter" class="day0916.MyMethodInterceptor"></bean>
- <!-- 定义切点切面 -->
- <bean id="myadvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
- <property name="pattern" value=".*"></property>
- <property name="advice" ref="mymethodinter"></property>
- </bean>
- <!-- 创建代理 -->
- <bean id="orderDAOProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <!-- 目标 -->
- <property name="target" ref="orderDAO"></property>
- <!-- 针对类代理 -->
- <property name="proxyTargetClass" value="true"></property>
- <!-- 增强 -->
- <property name="interceptorNames" value="myadvisor"></property>
- </bean>
- </beans>
测试类如下
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration("classpath:app2.xml")
- public class SpringTest {
- @Autowired
- @Qualifier("orderDAOProxy")
- private OrderDAO orderDAO;
- @Test
- public void test() {
- orderDAO.add();
- orderDAO.search();
- orderDAO.delete();
- }
- }
结果如下
环绕前增强
添加订单
环绕后增强
环绕前增强
查询订单
环绕后增强
环绕前增强
删除订单
环绕后增强
image.png
来源: http://www.jianshu.com/p/39c4bb9646e5