Spring 的 AOP 概述和底层实现

2019-06-20  本文已影响0人  希希里之海

Spring 的 AOP 概述和底层实现

1. 什么是 AOP

简单的来说就是:

生成和目标类一样的类或者继承目标类,生成子类,我们都把该类叫做代理类,然后通过代理方式在代理类中添加方法,以达到对目标类中的方法进行增强的目的。


2. AOP 相关术语

Joinpoint(连接点):

所谓连接点是指那些可以被拦截的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。

比如增删改查这些方法都可以增强,这些方法称为是连接点。

Pointcut(切入点):

指的是真正被拦截的点。

比如我们只想对类中的 save() 方法进行增强(做权限校验),save 方法称为是切入点。

Advice(通知/增强):

指拦截到 Joinpoint 之后所要做的事。

通知分为前置通知(方法执行之前)、后置通知(方法执行之后)、异常通知、最终通知、环绕通知(切面要完成的功能)

比如对 save 方法要进行权限校验,权限校验的方法称为是通知。

Introduction(引介):

引介是一种特殊的通知在不修改类代码的前提下,Introduction 可以在运行期为类动态地添加一些方法或 Field。

Target(目标对象):

代理(被增强)的目标对象。

Weaving(织入):

是指把增强(Advice)应用到目标对象(Target)来创建新的代理对象的过程。

比如将权限校验应用到 UserDaoImplsave 方法的这个过程。

Proxy(代理):

一个类被 AOP 织入增强后,就产生一个结果代理类。

Aspect(切面):

是切入点和通知(引介)的结合。


3. Spring 的底层实现原理

两种实现:
JDK 动态代理:
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 的接口。三个参数:

然后在测试类中 new 代理类,这样我们在测试类中调用实现类中的方法就相当于变成了调用动态代理类中的 invoke 方法。

注意:

JDK 动态代理是对实现接口类实行代理,建立一个实现目标类中方法的代理类。(面向接口)

具体代码:MyJdkProxy.java

CGLIB生成代理:
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 动态代理不同,是生成一个类来继承目标类。


4. 代理知识总结

具体代码:MyCglibProxy.java


附:

spring 核心包有四个:

上一篇 下一篇

猜你喜欢

热点阅读