简单的来说就是:
生成和目标类一样的类或者继承目标类,生成子类,我们都把该类叫做代理类,然后通过代理方式在代理类中添加方法,以达到对目标类中的方法进行增强的目的。
所谓连接点是指那些可以被拦截的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。
比如增删改查这些方法都可以增强,这些方法称为是连接点。
指的是真正被拦截的点。
比如我们只想对类中的 save()
方法进行增强(做权限校验),save
方法称为是切入点。
指拦截到 Joinpoint 之后所要做的事。
通知分为前置通知(方法执行之前)、后置通知(方法执行之后)、异常通知、最终通知、环绕通知(切面要完成的功能)
比如对 save
方法要进行权限校验,权限校验的方法称为是通知。
引介是一种特殊的通知在不修改类代码的前提下,Introduction 可以在运行期为类动态地添加一些方法或 Field。
代理(被增强)的目标对象。
是指把增强(Advice)应用到目标对象(Target)来创建新的代理对象的过程。
比如将权限校验应用到 UserDaoImpl
的 save
方法的这个过程。
一个类被 AOP 织入增强后,就产生一个结果代理类。
是切入点和通知(引介)的结合。
public class MyJdkProxy implements InvocationHandler{
private UserDao userDao;
public MyJdkProxy(UserDao userDao) {
this.userDao = userDao;
}
public Object createProxy() {
// 获得目标类
Object proxy = Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), this);
return proxy;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 对 save 进行增强
if ("save".equals(method.getName())) {
System.out.println("权限校验...");
// args 参数化,UserDao中方法列表
return method.invoke(userDao, args);
}
// invoke 调用 UserDao 中的方法
return method.invoke(userDao, args);
}
}
其中:
Proxy.newProxyInstance();
方法需要传入三个参数:类的加载器,类实现的接口,InvocationHandler
的接口。三个参数:
userDao.getClass().getClassLoader()
userDao.getClass().getInterfaces()
implements InvocationHandler
接口,再通过 this 实例化然后在测试类中 new 代理类,这样我们在测试类中调用实现类中的方法就相当于变成了调用动态代理类中的 invoke 方法。
注意:
JDK 动态代理是对实现接口类实行代理,建立一个实现目标类中方法的代理类。(面向接口)
public class MyCglibProxy implements MethodInterceptor{
private ProductDao productDao;
public MyCglibProxy(ProductDao productDao) {
this.productDao = productDao;
}
public Object createProxy() {
//1. 创建核心类
Enhancer enhancer = new Enhancer();
//2. 设置父类
enhancer.setSuperclass(productDao.getClass());
//3. 设置回调
enhancer.setCallback(this);
//4. 生成代理(子类)
Object proxy = enhancer.create();
return proxy;
}
//回调函数中实例化 MethodInterceptor 接口方法(intercept, 类似于 invoke 方法),通过 this
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if ("save".equals(method.getName())) {
System.out.println("权限校验=========");
}
// invokeSuper 调用父类 ProductDao 方法
return methodProxy.invokeSuper(proxy, args);
}
}
注意:
CGLIB 实现和 JDK 动态代理不同,是生成一个类来继承目标类。
spring 核心包有四个:
原文:https://www.cnblogs.com/weixuqin/p/11055915.html