我们一直在使用@Autowired
加上基于Java的Spring配置,取得了一些成功,但现在,我们正在失去控制。每个人都开始在各处添加 Autowiring 依赖项,从而产生循环和奇怪的错误。
因此我们正在考虑使用构造函数注入(inject)和 Spring 配置 Autowiring 。
旧:
class Bean {
@Autowired Foo foo;
}
@Configuration
@Import( FooCfg.class )
class BeanCfg {
@Bean public Bean bean() { return new Bean(); }
}
新:
class Bean {
public Bean(Foo foo) {...}
}
@Configuration
class BeanCfg {
@Autowired FooCfg fooCfg;
@Bean public Bean bean() { return new Bean(fooCfg.foo()); }
}
这非常有效(它促使人们分割 beans,而不是创建具有 10 多个构造函数参数的怪物)。
但是当 Bean
有一个用 @Transactional
注解的方法时,它会失败,因为 CGLIB 然后尝试创建一个代理,但由于找不到无参构造函数而失败.
这个问题有什么解决办法吗?
最佳答案
您有几种可能的解决方案
- 引入您的类的接口(interface)
- 将 Spring 版本至少升级到 4.0
- 添加
protected
无参数构造函数
引入接口(interface)
在为类引入接口(interface)时,您可以放弃使用 CgLib。然后 Spring 将能够使用围绕接口(interface)工作的 JDK 动态代理。它围绕已经存在的 bean 实例创建一个代理,并且该代理实现它所包装的类的所有接口(interface)。这样,您的类是否有无参数构造函数并不重要。
升级到 Spring 4
在 Spring 4.0 中添加了支持,以允许代理缺少无参数构造函数的类(请参阅 SPR-10594 )。要启用此功能,请升级您的 Spring 版本并添加 Objenesis在你的类路径中,Spring 4 附带了它自己的重新打包的 cglib 版本,因此不再需要它了。
需要注意的一件事是,您应该有一个没有逻辑的构造函数,如果您在构造函数中进行空检查或初始化逻辑,那么在 cglib 创建实例的情况下,它可能会失败。我怀疑它将 null 传递给所有构造函数参数(或基元的某些默认值)。
添加了protected
无参数构造函数
Cglib 需要能够创建一个用于包装实际类的实例。在类中拥有一个 protected 构造函数就足够了,以便 cglib 可以调用它。
关于Spring Java 配置、@Autowire 与构造函数注入(inject)、@Transactional 和 CGLIB,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25682757/