概述:AOP(面向切面/方面编程)。利用AOP可以对业务逻辑的各个部分进行隔离,从而使耦合度降低,提高程序的可重用性,提高开发效率。
通俗解释:不修改源代码,在主干功能里面扩展新功能。
基本术语:
- 连接点:类里面哪些方法可以增强,这些方法就称为连接点。
- 切入点:实际被真正增强的方法就被称为切入点。
- 通知/增强:
- 实际增强的逻辑部分被称为(通知/增强)(比如增加了日志功能,日志就是通知/增强)
- 通知/增强的类型
- 前置通知 @Before :在一个方法的前面执行的“通知/增强”部分
- 后置通知 @AfterReturning:在一个方法的后面执行的“通知/增强”部分。有异常时不执行
- 环绕通知 @Around:在一个方法的前面后面都执行的“通知/增强”部分
- 异常通知 @AfterThrowing:当这个方法出现异常就会执行“通知/增强”部分
- 最终通知 @After:相当于try…catch…中的finally,无论什么情况,最终一定会执行。
- 切面:是一个动作过程,把通知/增强应用到切入点的过程。
AOP底层原理
一、AOP 底层 动态管理概述
自己的理解:现实生活中,代理人可以帮助我们去处理更多的事情,比如何炅的代理人会帮助他发表对其它娱乐明星的生日祝福,会帮他安排行程表,然后他只要注重在自己的节目内容准备上就可以了。一个人完成的事情有限,我们通过代理人的一种方式,在本人精力有限的情况下,可以帮助我们更多的完成其它各种各样的事情。
创建动态代理有两种情况:
- 有接口的情况,使用 JDK 动态代理:就是创建一个实现接口类的代理对象。
- 没有接口的情况,使用 CGLIB 动态代理:没有接口就创建子类继承,在子类中扩展功能。
代码演示:AOP 底层 动态管理
细节:思考如何告诉程序你创建的这个是代理类?如何告诉代理类是哪个接口的需要代理?(如何告诉何炅,这是你的代理人?又如何告诉代理人你需要代理的人是何炅而不是汪峰?)
有接口的情况, JDK 动态代理
package com.wpc.spring5.collection;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class JDKProxy {
public static void main(String[] args) {
// 创建接口实现类的代理对象
Class[] interfaces = {UserDao.class}; // 接口列表
UserDaoImpl userDaoImpl = new UserDaoImpl();
// newProxyInstance 返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
// 参数:
// loader - 类加载器来定义代理类
// interfaces - 代理类实现的接口列表
// InvocationHandler h - 实现 InvocationHandler接口的调度方法调用的调用处理函数
UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoPeoxy(userDaoImpl));
int add = dao.add(1, 2);
System.out.println("result: " + add);
}
}
// 创建代理对象
class UserDaoPeoxy implements InvocationHandler{
// 创建是谁的代理对象,需要告诉程序
// 传递有参构造
private Object obj;
public UserDaoPeoxy(Object obj){
this.obj =obj;
}
// 编写增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 方法执行之前
System.out.println("方法执行之前 " + method.getName() + ": 传递的参数 " + Arrays.toString(args));
// 被增强的方法执行
Object res = method.invoke(obj, args);
// 方法执行之后
System.out.println("方法执行之后 "+obj);
return res;
}
}