博客
关于我
死磕Spring之AOP篇 - Spring AOP自动代理(三)创建代理对象
阅读量:439 次
发布时间:2019-03-06

本文共 2398 字,大约阅读时间需要 7 分钟。

Spring AOP 自动代理过程详解

在学习 Spring AOP 的过程中,我们需要深入理解其自动代理机制。Spring AOP 的核心是通过动态代理实现方法拦截和方法替换,这一过程主要由 AbstractAutoProxyCreator 类负责。在前面的文章中,我们分析了自动代理的入口和筛选Advisor的过程。本文将深入探讨如何为目标Bean创建代理对象。


创建代理对象的流程

AbstractAutoProxyCreator 类的 wrapIfNecessary 方法中,代理对象的创建主要分为以下几个步骤:

  • 检查是否需要代理

    首先,判断当前Bean是否需要代理。如果Bean已经被代理过(targetSourcedBeans 中存在)或不需要代理(advisedBeans 中标记为 false),则直接返回Bean。

  • 获取目标类

    如果需要代理,则获取目标Bean的类,并检查是否需要进行类代理(CGLIB动态代理)。默认情况下,proxyTargetClassfalse,表示优先使用JDK动态代理,但如果目标类没有实现可代理的接口,则会切换到CGLIB动态代理。

  • 获取适用的Advisor

    调用 getAdvicesAndAdvisorsForBean 方法,获取能够应用于目标Bean的所有Advisor。这些Advisor会根据 @Order 注解进行排序,优先级为:AspectJAfterThrowingAdvice > AspectJAfterReturningAdvice > AspectJAfterAdvice > AspectJAroundAdvice > AspectJMethodBeforeAdvice

  • 创建代理对象

    如果有适用的Advisor,则通过 createProxy 方法创建代理对象。以下是具体的实现细节:


  • 代理工厂的创建

    代理对象的创建主要由 ProxyFactory 类负责。ProxyFactory 类的作用是创建动态代理对象,具体由 DefaultAopProxyFactory 实现。

    1. 选择代理类型

    DefaultAopProxyFactory 根据以下条件选择代理类型:

    • 如果 proxy-target-classfalse,优先使用JDK动态代理。如果目标类没有实现可代理的接口,则切换到CGLIB动态代理。
    • 如果 proxy-target-classtrue,优先使用CGLIB动态代理。如果目标类本身是一个接口,则仍使用JDK动态代理。

    2. 创建动态代理

    JdkDynamicAopProxyObjenesisCglibAopProxy 是两种主要的动态代理实现类。

    JDK动态代理(JdkDynamicAopProxy)

    • 实现JdkDynamicAopProxy 实现了 InvocationHandler 接口,通过 Proxy.newProxyInstance 方法创建代理对象。
    • 特点:无需修改目标类,直接通过拦截方法调用目标对象的方法。拦截器由 DynamicAdvisedInterceptor 实现。

    CGLIB动态代理(ObjenesisCglibAopProxy)

    • 实现ObjenesisCglibAopProxy 通过 Enhancer 创建代理类。CGLIB会生成目标类的超类,避免直接修改目标类。
    • 特点:支持通过构造器实例化代理对象,适用于一些特殊场景,如序列化、远程调用等。

    动态代理的实现细节

    1. InvocationHandler 的实现

    无论是JDK动态代理还是CGLIB动态代理,代理对象都实现了 InvocationHandler 接口,用于拦截目标对象的方法调用。拦截器的逻辑主要集中在以下几个方面:

    • 方法拦截:根据Advisor的配置,决定是否执行目标方法或替换目标方法。
    • 返回值处理:对目标方法的返回结果进行加工,例如在 equalshashCode 方法中添加代理对象的信息。

    2. Callback 的配置

    在CGLIB动态代理中,Callback 数组用于定义方法拦截器的逻辑。具体来说,Callback 的类型和顺序决定了拦截器的行为。以下是常见的 Callback 类型:

    • AOP_PROXY:进行AOP代理的通用拦截器。
    • INVOKETARGET:执行目标方法。
    • NO_OVERRIDE:空的 Callback,用于不需要拦截的方法(如 finalize())。
    • DISPATCH_TARGET:目标对象调度器,用于获取目标对象。
    • DISPATCH_ADVISED:配置管理器的调度器,用于执行 AdvisedSupport 的方法。

    总结

    Spring AOP 的自动代理过程可以分为以下几个关键步骤:

  • 筛选Advisor:通过 ClassFilterMethodMatcher 确定哪些Advisor适用于目标Bean。
  • 创建代理对象:根据选择的动态代理类型(JDK或CGLIB),通过 ProxyFactory 创建代理对象。
  • 配置代理工厂:设置目标类来源、Advisor数组以及拦截器逻辑。
  • 其中,CGLIB动态代理的实现相对复杂,涉及 Objenesis 库的实例化和 Callback 的配置。以下是两种动态代理的主要区别:

    • JDK动态代理:简单易用,适用于大多数场景。
    • CGLIB动态代理:适用于需要通过构造器实例化代理对象或对性能有特殊要求的情况。

    通过本文的分析,我们可以清晰地看到Spring AOP如何在背后为Bean创建代理对象,从而实现AOP的功能。如果需要进一步理解动态代理的实现细节,可以继续阅读下一篇文章,探讨 DynamicAdvisedInterceptor 拦截器的工作原理。

    转载地址:http://gksyz.baihongyu.com/

    你可能感兴趣的文章
    nuget.org 无法加载源 https://api.nuget.org/v3/index.json 的服务索引
    查看>>
    Nuget~管理自己的包包
    查看>>
    NuGet学习笔记001---了解使用NuGet给net快速获取引用
    查看>>
    nullnullHuge Pages
    查看>>
    NullPointerException Cannot invoke setSkipOutputConversion(boolean) because functionToInvoke is null
    查看>>
    null可以转换成任意非基本类型(int/short/long/float/boolean/byte/double/char以外)
    查看>>
    Numix Core 开源项目教程
    查看>>
    numpy
    查看>>
    NumPy 库详细介绍-ChatGPT4o作答
    查看>>
    NumPy 或 Pandas:将数组类型保持为整数,同时具有 NaN 值
    查看>>
    numpy 或 scipy 有哪些可能的计算可以返回 NaN?
    查看>>
    numpy 数组 dtype 在 Windows 10 64 位机器中默认为 int32
    查看>>
    numpy 数组与矩阵的乘法理解
    查看>>
    NumPy 数组拼接方法-ChatGPT4o作答
    查看>>
    numpy 用法
    查看>>
    Numpy 科学计算库详解
    查看>>
    Numpy.fft.fft和numpy.fft.fftfreq有什么不同
    查看>>
    Numpy.ndarray对象不可调用
    查看>>
    Numpy.VisibleDeproationWarning:从不整齐的嵌套序列创建ndarray
    查看>>
    Numpy:按多个条件过滤行?
    查看>>