如何做直播类网站,海口cms建站系统,备案资料网站查询,机械配件网站建设上一篇SpringAOP专栏一《使用教程篇》-CSDN博客介绍了SpringAop如何使用#xff0c;这一篇文章就会介绍Spring AOP 的底层实现原理#xff0c;并通过源代码解析来详细阐述其实现过程。
前言
Spring AOP 的实现原理是基于动态代理和字节码操作的。不了解动态代理和字节码操作…上一篇SpringAOP专栏一《使用教程篇》-CSDN博客介绍了SpringAop如何使用这一篇文章就会介绍Spring AOP 的底层实现原理并通过源代码解析来详细阐述其实现过程。
前言
Spring AOP 的实现原理是基于动态代理和字节码操作的。不了解动态代理和字节码操作的读者可以先看一下这篇文章java中的反射和代理模式-CSDN博客
实现原理
下面我会基于在使用SpringAOP进行逻辑增强时各个核心类的执行顺序进行底层原理的剖析
实现代理和切面逻辑的核心类执行顺序如下 1.Bean 实例化阶段 BeanPostProcessor在 Bean 实例化之后进行初始化前的处理。其中AbstractAutoProxyCreator 是一个重要的 BeanPostProcessor 实现类用于自动创建代理对象。 2.切面织入阶段 AdvisedSupport封装了切面逻辑和目标对象信息。ProxyFactoryBean生成代理对象的工厂类。AopProxyFactoryAOP 代理对象的工厂接口。AopProxyAOP 代理对象的核心接口定义了获取代理对象的方法。CglibAopProxy基于 CGLIB 的动态代理实现类。DynamicAdvisedInterceptorCGLIB 动态代理的回调函数实现类用于触发切面逻辑的执行。 3.方法拦截与执行阶段 ProxyMethodInvocation代理方法调用的核心类封装了目标对象方法和参数信息。ReflectiveMethodInvocation反射调用目标方法的类是 ProxyMethodInvocation 的具体实现类。MethodInvocationInterceptor方法拦截器接口定义了拦截器的方法执行逻辑。MethodInterceptorCGLIB 库中的接口被 MethodInvocationInterceptor 实现。 Bean 实例化阶段
在service bean的创建过程中(也就是getBean(service))AOP通过BeanPostProcess后置处理器操作进行介入 分为2种情况 用户自定义了targetSource则bean的创建(实例化、填充、初始化)均由用户负责Spring Ioc不会在管该代理目标对象traget这种情况基本上不会发生很多人用了几年Spring可能都不知道有它的存在正常情况下都是Spring Ioc完成代理对象target的实例化、填充、初始化。然后在初始化后置处理器中进行介入对bean也就是service进行代理 下面是Bean示例化的流程图 切面织入阶段
Spring AOP 是构建在动态代理基础上因此 Spring 对 AOP 的支持局限于方法级别的拦截。
在这个阶段会读取相关的SpringAOP的配置如何将切面逻辑和目标对象信息封装到AdvisedSupport中再通过ProxyFactoryBean生成代理对象的工厂类根据目标对象是否实现接口来调用JDK动态代理还是Cglib代理。
下面详细介绍一下两者代理方式的实现源码
Spring AOP 动态代理实现 默认情况下实现了接⼝的类使⽤ AOP 会基于 JDK ⽣成代理类没有实现接⼝的类会基于 CGLIB ⽣成代理类。JDK ProxyJDK 动态代理CGLIB Proxy默认情况下 Spring AOP 都会采用 CGLIB 来实现动态代理因为效率高CGLIB 实现原理通过继承代理对象来实现动态代理的子类拥有父类的所有功能CGLIB 缺点不能代理最终类也就是被 final 修饰的类 JDK动态代理 JDK 动态代理是 Java 自带的动态代理实现方式。使用JDK动态代理时需要目标对象实现至少一个接口。JDK 动态代理会在运行时生成一个实现了目标对象接口的代理类该代理类会在目标对象方法执行前后插入切面代码。 下面是JdkDynamicAopProxy类的部分源码感兴趣的读者可以自己去看看我这里就不一一截图给大家看了。 如果读者看源码如果有困难可以看一下这个我简化了的JdkDynamicAopProxy类。这个类我保留了主要逻辑把一些提高代码健壮性的部分去掉了。
JdkDynamicAopProxy 类的主要作用是将切面逻辑织入到目标对象的方法调用中。当使用基于接口的代理方式时Spring AOP 使用 JDK 动态代理来创建代理对象。JdkDynamicAopProxy 类会根据配置的切面信息动态地生成一个代理对象并将切面逻辑织入到该代理对象的方法调用中。
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {private final AdvisedSupport advised;public JdkDynamicAopProxy(AdvisedSupport advised) {this.advised advised;}Overridepublic Object getProxy() {return Proxy.newProxyInstance(getClass().getClassLoader(),advised.getTargetSource().getInterfaces(),this);}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {MethodInterceptor methodInterceptor advised.getMethodInterceptor();MethodInvocation methodInvocation new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(),method,args,methodInterceptor,advised.getTargetSource().getTargetClass());return methodInvocation.proceed();}
}在该代码中JdkDynamicAopProxy 类实现了 AopProxy 和 InvocationHandler 接口。 AopProxy 接口是 Spring AOP 提供的代理接口它定义了获取代理对象的方法。JdkDynamicAopProxy 类通过实现该接口提供了基于 JDK 动态代理的代理对象获取功能。 InvocationHandler 接口是 JDK 提供的反射 API 中的一部分它定义了一个 invoke 方法用于在代理对象上调用被代理方法。JdkDynamicAopProxy 类实现了 InvocationHandler 接口通过重写 invoke 方法实现对被代理方法的增强逻辑。
下面是对简化了的JdkDynamicAopProxy类的详细解读 AdvisedSupport 类型的属性 advised表示该代理对象所依赖的 AdvisedSupport 对象该对象包含了切面配置信息。 构造函数 JdkDynamicAopProxy(AdvisedSupport advised)接收一个 AdvisedSupport 对象作为参数并将其赋值给 advised 属性。 getProxy() 方法实现了 AopProxy 接口中的方法用于获取代理对象。它通过调用 Proxy.newProxyInstance() 方法创建代理对象。 getClass().getClassLoader() 获取当前类的类加载器。advised.getTargetSource().getInterfaces() 获取目标对象实现的接口数组。this 表示使用当前对象作为代理对象的 InvocationHandler。 invoke(Object proxy, Method method, Object[] args) 方法实现了 InvocationHandler 接口中的方法拦截目标对象方法的调用并进行增强逻辑。 首先从 advised 对象中获取 MethodInterceptor 实例即切面逻辑。然后创建一个 ReflectiveMethodInvocation 实例传入目标对象、目标方法、方法参数、切面逻辑和目标对象的类信息。最后调用 methodInvocation.proceed() 方法执行切面逻辑并返回方法的执行结果。 CGLIB 代理 CGLIB 代理是一个基于字节码操作的代理方式它可以为没有实现接口的类创建代理对象。CGLIB 代理会在运行时生成一个目标对象的子类并覆盖其中的方法以实现AOP的功能。 下面是CglibAopProxy类的部分源代码感兴趣的读者可以自己去看看我这里就不一一截图给大家看了。 如果读者看源码如果有困难可以看一下这个我简化了的CglibAopProxy类。这个类我保留了主要逻辑对代码进行了简化。
public class CglibAopProxy implements AopProxy {private final AdvisedSupport advised;public CglibAopProxy(AdvisedSupport advised) {this.advised advised;}Overridepublic Object getProxy() {Enhancer enhancer new Enhancer();enhancer.setSuperclass(advised.getTargetSource().getTargetClass());enhancer.setCallback(new DynamicAdvisedInterceptor(advised));return enhancer.create();}private static class DynamicAdvisedInterceptor implements MethodInterceptor {private final AdvisedSupport advised;public DynamicAdvisedInterceptor(AdvisedSupport advised) {this.advised advised;}Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {MethodInvocation methodInvocation new CglibMethodInvocation(advised.getTargetSource().getTarget(),method,args,proxy,advised.getMethodInterceptor(),advised.getTargetSource().getTargetClass());return methodInvocation.proceed();}}
}
CglibAopProxy 类主要有以下作用 生成代理对象CglibAopProxy 根据目标对象和切面逻辑生成一个代理对象。与 JDK 动态代理不同CGLIB 代理不需要目标对象实现接口。 增强方法逻辑通过继承目标对象CglibAopProxy 重写目标对象的方法并在方法中添加切面逻辑。这样在调用代理对象的方法时会先执行切面逻辑然后再调用目标对象的原始方法。 拦截方法调用CglibAopProxy 使用 MethodInterceptor 接口来定义切面逻辑并将其应用于生成的代理对象。在代理对象的方法调用过程中切面逻辑会被触发从而实现横切关注点的功能如事务管理、日志记录等。 高性能的代理相较于 JDK 动态代理CGLIB 代理使用了字节码生成技术生成的代理对象是目标对象的子类。这种方式避免了通过反射调用目标对象的方法提供了更高的执行性能。 下面是CglibAopProxy类的详细解读 CglibAopProxy 类实现了 AopProxy 接口该接口定义了获取代理对象的方法 getProxy()。 CglibAopProxy 类的构造方法需要一个 AdvisedSupport 对象作为参数AdvisedSupport 是 Spring AOP 框架中的核心类用于保存切面逻辑和目标对象信息。 getProxy() 方法中首先实例化了 Enhancer 对象Enhancer 是 CGLIB 库中的主要类用于生成代理对象。 setSuperclass() 方法将目标对象的类设置为要生成的代理类的父类这样代理类就可以继承目标类的所有非私有方法。 setCallback() 方法用于设置代理类的回调函数即在代理类的方法调用时会触发回调函数中的逻辑。 DynamicAdvisedInterceptor 类实现了 MethodInterceptor 接口这个接口是 CGLIB 库中的接口用于定义代理类的回调函数。 intercept() 方法是 DynamicAdvisedInterceptor 类的核心方法。当代理类的方法被调用时intercept() 方法会被触发。在该方法中首先将目标对象的方法和参数封装成 MethodInvocation 对象然后调用其 proceed() 方法从而触发切面逻辑的执行。 CglibMethodInvocation 类是 MethodInvocation 接口的实现类用于封装目标对象的方法和参数信息。 方法拦截与执行阶段
该阶段的实际执行流程为 当代理对象的方法被调用时会创建一个 ProxyMethodInvocation 对象并将目标对象、目标方法、方法参数等信息传递给它。 ProxyMethodInvocation 继承了 ReflectiveMethodInvocation 类因此它可以通过反射调用目标方法。 在拦截器链的创建过程中AdvisorChainFactory 会根据切点和通知创建 Advisor 链即将所有与目标方法匹配的切面的方法拦截器添加到拦截器链中。 当 ProxyMethodInvocation 执行目标方法时它会依次遍历拦截器链中的每个方法拦截器。 每个方法拦截器在方法调用前后执行自己的逻辑可以实现前置通知、后置通知、异常处理和返回通知等功能。 方法拦截器的执行顺序与它们在拦截器链中的顺序一致。在方法调用之前拦截器依次执行前置通知在方法调用之后拦截器依次执行后置通知如果方法发生异常拦截器执行异常处理逻辑最后拦截器执行返回通知。 下面我来分析一下SpringAOP的拦截器
SpringAOP的拦截器
我们先来了解一下拦截器的执行属性如下图所示 接下来看一下AOP拦截器执行原理拦截器是如何保证不同通知注解下的方法的执行顺序的呢 在 Spring AOP 中拦截器链的执行顺序是由 AdvisedSupport 类中的方法获取的。AdvisedSupport 包含了代理对象需要的所有信息包括目标对象、代理接口、拦截器等。其中拦截器链的创建和执行是在 ExposeInvocationInterceptor 这个拦截器中完成的。 在创建拦截器链时AdvisorChainFactory 会根据切面的顺序将各个切面的拦截器顺序组合成一个拦截器链。这样就可以保证 before 在 after 之前执行因为在创建拦截器链的过程中会按照切面的顺序将各个切面的拦截器依次添加到链中最终形成一个有序的拦截器链。 另外对于同一个方法的多个切面Spring AOP 会根据切面的顺序将它们的拦截器依次添加到拦截器链中从而保证了它们的执行顺序。这样就可以保证 find 方法的执行顺序符合切面的定义顺序。 因此通过 Spring AOP 框架内部对拦截器链的创建和执行机制的设计可以保证拦截器的执行顺序满足业务需求确保了 before 在 after 之前执行并且保证了多个拦截器的执行顺序。