• 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配置已无效。
  • 相关阅读:
    moment.js常用时间示例,时间管理
    RabbitMQ用户增删及权限控制
    CDN概念基本介绍
    在LinkedIn的 Kafka 生态系统
    发行说明
    Kafka 1.0版本发布
    redis应用场景及实例
    Redis哨兵集群
    redis-订阅与发布
    redis事务
  • 原文地址:https://www.cnblogs.com/chihirotan/p/14425522.html
Copyright © 2020-2023  润新知