【问题标题】:What are the drawbacks of CGLIB proxy over dynamic proxy in Spring AOP?Spring AOP中CGLIB代理优于动态代理的缺点是什么?
【发布时间】:2021-03-24 20:11:30
【问题描述】:

据我了解,Spring AOP一般涉及到:

  • 接口的动态代理
  • CGLIB 代理用于那些没有(最终方法和类除外)

为什么不一直使用 CGLIB 代理?我希望获得以下收益:

  • 由于它是在编译期间完成的,因此应该比动态代理获得性能提升
  • 没有要求接口的限制因素
    • 如果您在某些服务工厂中返回 impl 类,可能会绕过代理 以无需编译的可配置性为代价。

【问题讨论】:

    标签: spring spring-aop cglib


    【解决方案1】:

    我不确定我是否理解您在问题中提出的 CGLIB 的好处。 动态代理和CGLIB都是在运行时创建的,与编译时完全无关。

    基本上,CGLIB 的主要缺点是性能。

    根据领域的不同,性能有两个方面或多或少重要:

    • 创建代理对象的成本
    • 代理上的方法调用成本。

    现在,在这两种情况下,动态代理机制都比 CGLIB 代理更轻量级。这就是为什么 spring 到版本 5(在问题标签中提到)试图创建动态代理,如果有一个接口,并且只有当它不可能用 CGLIB 包装真实对象时。

    这在 Spring 5 中发生了变化,在任何情况下都支持使用 CGLIB,但仍有一个标志可以恢复旧行为。

    有趣的是,CGLIB 有一种你没有提到的优势,这对 Spring 很重要(嗯,也许这就是 Spring 5 中行为变化的原因,我不能肯定地说):

    许多公司不费心为服务创建接口并直接通过实现工作,或者即使他们这样做了 - 他们也不使用接口注入:

    
    public interface MyService {
       void foo();
    }
    
    @Component
    public class MyServiceImpl implements MyService {
        public void foo() {... whatever...}
    }
    
    @Component
    public class AnotherService {
    
     @Autowired // note, this is not an injection by inteface
     private MyServiceImpl service;
    
     public void bar() {
        // do something
        service.foo(); 
        // do something else
    
      }
    }
    

    现在,如果您将使用动态代理(如果应用程序代码使用接口注入,通常可以使用该代理) - 您将生成实现接口 MyService 但无法注入的东西进入AnotherService,因为生成的代理没有扩展MyServiceImpl 类。在这种情况下,CGLIB 是唯一可行的解​​决方案。

    【讨论】: