在 Spring AOP 中,CGLIB 代理相对于动态代理有哪些缺点?

Dan*_*erg 6 spring spring-aop cglib

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

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

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

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

Mar*_*nik 2

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

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

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

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

现在,在这两种情况下,动态代理机制都比 CGLIB 代理轻量得多。这就是为什么 spring up 版本 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

  }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果您将使用动态代理(如果应用程序代码使用接口注入,则通常可以使用动态代理) - 您将生成实现该接口MyService但无法注入的内容AnotherService,因为生成的代理不不延长MyServiceImpl班级。在这种情况下,CGLIB 是唯一可行的解​​决方案。