Wicket @SpringBean和Spring @Autowired通过构造函数

时间:2016-02-07 23:42:36

标签: java spring dependency-injection wicket

我有一个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一起工​​作?

3 个答案:

答案 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() {}

}

实际上,您不需要声明一个空构造函数。我这样做只是为了清楚。请注意,BlogRepositoryBlogPostRepository应声明为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));
}