Spring Java配置,@ Autowire与构造函数注入,@ Transaction和CGLIB

Aar*_*lla 3 spring proxy-classes transactional autowired cglib

我们一直在使用@Autowired基于Java的Spring配置并取得了一些成功,但现在我们失去了控制权.每个人都开始在任何地方添加自动连接的依赖项,创建周期和奇怪的错误.

所以我们正在考虑使用构造函数注入和Spring配置的自动装配.

旧:

class Bean {
   @Autowired Foo foo;
}

@Configuration
@Import( FooCfg.class )
class BeanCfg {
   @Bean public Bean bean() { return new Bean(); }
}
Run Code Online (Sandbox Code Playgroud)

新:

class Bean {
   public Bean(Foo foo) {...}
}

@Configuration
class BeanCfg {
   @Autowired FooCfg fooCfg;
   @Bean public Bean bean() { return new Bean(fooCfg.foo()); }
}
Run Code Online (Sandbox Code Playgroud)

这非常有效(并且它驱使人们分割bean而不是创建具有10个以上构造函数参数的怪物).

但是当Bean有一个方法注释时它会失败,@Transactional因为CGLIB然后尝试创建一个失败的代理,因为它找不到无参构造函数.

这是什么解决方案?

M. *_*num 5

您有几种可能的解决方案

  1. 介绍您的类的接口
  2. 将Spring版本升级到至少4.0
  3. 添加protectedno-arg构造函数

介绍接口

在为类引入接口时,可以删除CgLib的用法.然后Spring将能够使用JDK Dynamic Proxies来解决接口问题.它围绕一个已经存在的bean实例创建一个代理,该代理实现了它所包装的类的所有接口.这样,你的类是否有一个无参数构造函数并不重要.

升级到Spring 4

在Spring 4.0中,添加了支持以允许使用缺少的无参数构造函数来代理类(参见SPR-10594).为了实现Spring版本的升级并将Objenesis添加到类路径中,Spring 4附带了自己的重新打包的cglib版本,因此不再需要它了.

需要注意的一点是,如果你在构造函数中进行空检查或初始化逻辑,你应该有一个没有逻辑的构造函数,在cglib创建实例的情况下它可能会失败.我怀疑它将null传递给所有构造函数参数(或者一些默认的基元).

添加了protectedno-arg构造函数

Cglib需要能够创建一个用于包装实际类的实例.protected在类中有一个构造函数就足够了,这样cglib就可以调用它.

  • Spring使用它,如果objenesis在类路径上.阅读答案中链接的问题. (2认同)