zoukankan      html  css  js  c++  java
  • Spring 5 AOP 代理对象方式默认改用 CGLIB 了吗?

    1. 真的假的?查阅文档

    刚看到这个说法的时候,我是保持怀疑态度的。

    大家都知道 Spring5 之前的版本 AOP 在默认情况下是使用 JDK 动态代理的,那是不是 Spring5 版本真的做了修改呢?于是我打开 Spring Framework 5.x 文档,再次确认了一下:

    文档地址:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/core.html#aop

    简单翻译一下。Spring AOP 默认使用 JDK 动态代理,如果对象没有实现接口,则使用 CGLIB 代理。当然,也可以强制使用 CGLIB 代理。也就是没有改变

    2 .SpringBoot 2.x 代码示例

    public interface ClassInterE{
        public void funA();
    }
    
    @Component
    public class ClassSonE implements ClassInterE{
        @Transactional
        public void funA(){}
        public void funB(){}
    }

     

    ClassSonE实现了ClassInterE接口,同时使用@Transactional对ClassSonE#funA方法进行前置增强拦截。

    从运行结果来看,这里的确使用了 CGLIB 代理而不是 JDK 动态代理。

    难道真的是文档写错了?!

    @EnableAspectJAutoProxy 源码注释

    在 Spring Framework 中,是使用@EnableAspectJAutoProxy注解来开启 Spring AOP 相关功能的。Spring Framework 5.2.0.RELEASE 版本@EnableAspectJAutoProxy注解源码如下:

     通过源码注释我们可以了解到:在 Spring Framework 5.2.0.RELEASE 版本中,proxyTargetClass的默认取值依旧是false,默认还是使用 JDK 动态代理。难道文档和源码注释都写错了?!

    Spring Framework 5.x 整理一下思路

    1. 有人说 Spring5 开始 AOP 默认使用 CGLIB 了
    2. Spring Framework 5.x 文档和  @EnableAspectJAutoProxy源码注释都说了默认是使用 JDK 动态代理
    3. 程序运行结果说明,即使继承了接口,设置 proxyTargetClass为 false,程序依旧使用 CGLIB 代理

    3 . 示例程序是使用 SpringBoot 来运行的,那如果不用 SpringBoot,只用 Spring Framework 会怎么样呢?

     运行结果表明:在 Spring Framework 5.x 版本中,如果类实现了接口,AOP 默认还是使用 JDK 动态代理。

    再探 SpringBoot 2.x

    1. Spring5 AOP 默认依旧使用 JDK 动态代理,官方文档和源码注释没有错。
    2. SpringBoot 2.x 版本中,AOP 默认使用 cglib,且无法通过 proxyTargetClass进行修改。
    3. 那是不是 SpringBoot 2.x 版本做了一些改动呢?

    源码分析

    源码分析,找对入口很重要。那这次的入口在哪里呢?

    @SpringBootApplication是一个组合注解,该注解中使用@EnableAutoConfiguration实现了大量的自动装配。

    EnableAutoConfiguration也是一个组合注解,在该注解上被标志了@Import。关于@Import注解的详细用法,可以参看笔者之前的文章:https://mp.weixin.qq.com/s/7arh4sVH1mlHE0GVVbZ84Q

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {}

    在 Spring Framework 4.x 版本中,这是一个空接口,它仅仅是继承了ImportSelector接口而已。而在 5.x 版本中拓展了DeferredImportSelector接口,增加了一个getImportGroup方法:

    在这个方法中返回了AutoConfigurationGroup类。这是AutoConfigurationImportSelector中的一个内部类,他实现了DeferredImportSelector.Group接口。

    在 SpringBoot 2.x 版本中,就是通过AutoConfigurationImportSelector.AutoConfigurationGroup#process方法来导入自动配置类的。

     

    通过断点调试可以看到,和 AOP 相关的自动配置是通过org.springframework.boot.autoconfigure.aop.AopAutoConfiguration来进行配置的。

     

    真相大白

    看到这里,可以说是真相大白了。在 SpringBoot2.x 版本中,通过AopAutoConfiguration来自动装配 AOP。

    默认情况下,是肯定没有spring.aop.proxy-target-class这个配置项的。而此时,在 SpringBoot 2.x 版本中会默认使用 Cglib 来实现。

    5. SpringBoot 2.x 中如何修改 AOP 实现

    通过源码我们也就可以知道,在 SpringBoot 2.x 中如果需要修改 AOP 的实现,需要通过spring.aop.proxy-target-class这个配置项来修改。

    #在application.properties文件中通过spring.aop.proxy-target-class来配置
    spring.aop.proxy-target-class=false

    总结

    1. Spring 5.x 中 AOP 默认依旧使用 JDK 动态代理。
    2. SpringBoot 2.x 开始,为了解决使用 JDK 动态代理可能导致的类型转化异常而默认使用 CGLIB。
    3. 在 SpringBoot 2.x 中,如果需要默认使用 JDK 动态代理可以通过配置项 spring.aop.proxy-target-class=false来进行修改, proxyTargetClass配置已无效。
  • 相关阅读:
    LeetCode 230. 二叉搜索树中第K小的元素(Kth Smallest Element in a BST)
    LeetCode 216. 组合总和 III(Combination Sum III)
    LeetCode 179. 最大数(Largest Number)
    LeetCode 199. 二叉树的右视图(Binary Tree Right Side View)
    LeetCode 114. 二叉树展开为链表(Flatten Binary Tree to Linked List)
    LeetCode 106. 从中序与后序遍历序列构造二叉树(Construct Binary Tree from Inorder and Postorder Traversal)
    指针变量、普通变量、内存和地址的全面对比
    MiZ702学习笔记8——让MiZ702变身PC的方法
    你可能不知道的,定义,声明,初始化
    原创zynq文章整理(MiZ702教程+例程)
  • 原文地址:https://www.cnblogs.com/chihirotan/p/14425522.html
Copyright © 2011-2022 走看看