我有一个Wicket面板,我想在其中使用@SpringBean注入bean
public class SomePanel extends Panel {
@SpringBean
private BlogSummaryMailGenerator blogSummaryMailGenerator;
}
但是这个BlogSummaryMailGenerator通过如下定义的构造函数注入:
@Component
public class BlogSummaryMailGenerator {
private BlogRepository blogRepository;
private BlogPostRepository blogPostRepository;
@Autowired
public BlogSummaryMailGenerator(BlogRepository blogRepository,
BlogPostRepository blogPostRepository) {
this.blogRepository = blogRepository;
this.blogPostRepository = blogPostRepository;
}
}
当SomePanel被实例化时,我得到一个异常
Caused by: java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
at net.sf.cglib.proxy.Enhancer.emitConstructors(Enhancer.java:721) ~[cglib-3.1.jar:na]
at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:499) ~[cglib-3.1.jar:na]
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25) ~[cglib-3.1.jar:na]
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216) ~[cglib-3.1.jar:na]
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377) ~[cglib-3.1.jar:na]
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285) ~[cglib-3.1.jar:na]
at org.apache.wicket.proxy.LazyInitProxyFactory.createProxy(LazyInitProxyFactory.java:191) ~[wicket-ioc-7.2.0.jar:7.2.0]
将空的no-args构造函数添加到BlogSummaryMailGenerator解决了这个问题,但仅添加此类代码以使注入工作是错误的,我想避免它。
如何通过构造函数使用注入使@SpringBean与bean一起工作?
答案 0 :(得分:6)
真正的问题在于CGLIB。它需要一个默认构造函数才能创建代理实例。真正的Spring bean是由Spring单独创建的,没有这样的限制。就我记忆而言,CGLIB所需的默认构造函数甚至可以是private
。
另一个解决方案是为此bean使用接口。然后Wicket将使用JDK代理而不是CGLIB,在这种情况下,实现中不需要默认构造函数。
答案 1 :(得分:4)
为了能够在 Wicket 组件中利用@SpringBean
的构造函数注入,您只需将Objenesis添加到编译时依赖项中。
Objenesis 是一个鲜为人知的字节代码操作库(与 CGLIB 一起提供 Wicket )能够创建没有默认(无args)构造函数的类的代理对象。如果将它作为编译依赖项添加到项目中,那么 Wicket 将切换它的内部延迟初始化代理创建逻辑,以利用 Objenesis (而不是 CGLIB 不需要args构造函数。不幸的是,这个功能没有记录,但我可以确认它适用于我的情况。
答案 2 :(得分:0)
错误信息非常清楚。 Wicked尝试使用BlogSummaryMailGenerator
库为CGLIB
创建代理类实例。既然你没有(或你不能)为构造函数提供参数,它就会查找没有参数的contstructor。但它不能,而且你会得到错误。
只需用属性注入替换构造函数注入,并创建无参数构造函数:
@Component
public class BlogSummaryMailGenerator {
@Autowired
private BlogRepository blogRepository;
@Autowired
private BlogPostRepository blogPostRepository;
public BlogSummaryMailGenerator() {}
}
实际上,您不需要声明一个空构造函数。我这样做只是为了清楚。请注意,BlogRepository
和BlogPostRepository
应声明为bean(标有@Component
注释,或在Spring配置中创建为@Bean
。
<强>更新强>
在SpringComponentInjector
中添加WebApplication.init()
时,可以为第三个参数指定false
,这意味着'wrapInProxies'。 Wicket永远不会将Spring bean包装在porxy中,你可以使用@Autowired
作为构造函数。
@Override
public void init()
{
super.init();
AnnotationConfigApplicationContext springContext =
new AnnotationConfigApplicationContext();
springContext.register(SpringConfig.class);
springContext.refresh();
getComponentInstantiationListeners().add(new SpringComponentInjector(this,
springContext, false));
}