Spring Java 配置、@Autowire 与构造函数注入(inject)、@Transactional 和 CGLIB

标签 spring autowired transactional proxy-classes cglib

我们一直在使用@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 然后尝试创建一个代理,但由于找不到无参构造函数而失败.

这个问题有什么解决办法吗?

最佳答案

您有几种可能的解决方案

  1. 引入您的类的接口(interface)
  2. 将 Spring 版本至少升级到 4.0
  3. 添加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/

相关文章:

java - 当关键代码语句中未实现日志记录时,更好的调试方法

java - 使用 Spring 服务的构建器类

Grails .save(刷新 : true) behaves the same with . save()

spring - 如何在调用构造函数之前注入(inject) spring @Value 注释值?

java - 无法在父项目中使用外部 jar 文件的 Autowiring 类

spring - 使用 Spring 2.5 从外部事务控制内部事务设置

java - Spring事务和多表回滚

java - Spring MVC。方法参数字段的默认值

java - 如何使用端口号来保护 Web 请求

java - ResultSetExtractor 中 getInt 的性能问题