【问题标题】:Inject repository in spring bean created programmatically在以编程方式创建的 Spring bean 中注入存储库
【发布时间】:2019-07-08 16:14:30
【问题描述】:

我正在尝试为实体类编写自定义 JSF 转换器。 我在我的项目中使用了 spring-data 和 spring-boot。

知道我有很多类看起来像`this:

 @Component("myFirstConverter")
 class MyFirstConverter implements Converter {
    @Autowired
    private MyFirstRepository myFirstRepository;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, 
                              String value) {
    return myFirstRepository.findOne(Long.parseLong(value));
    }
    //...

}

我创建了自定义类 EntityConverter。它适用于 CrudRepository。但我不明白如何以编程方式创建 bean 数组并注入到每个 bean 对应的存储库中。

知道我试图用这段代码编写 @Configuration 类:

 @Configuration
 class MyConfig extends WebMvcConfigurerAdapter  
       @Bean
       public static BeanFactoryPostProcessor registerConverters(ApplicationContext context) {
    Map<String, Class<? extends CrudRepository>> converterBeans = new HashMap<>();
    converterBeans.put("firstEntity", firstEntityRepository.class);
    converterBeans.put("secondEntity", secondEntity.class);
    return factory -> {
        for (val entry : converterBeans.entrySet()) {
            CrudRepository bean = context.getBean(entry.getValue()
            factory.registerSingleton(entry.getKey()
            .concat("Converter"), new EntityConverter(
                    entry.getKey(), bean));
        }
    };

但它不起作用。应用程序初始化失败。

 19:07:59.546 [WARN ] o.s.c.support.AbstractApplicationContext:551  - 
    Exception encountered during context initialization - cancelling 
    refresh attempt: 
    org.springframework.beans.factory.BeanCreationException: Error 
    creating bean with name 'myFirstRepository': Cannot create inner bean 
    '(inner bean)#1fdfafd2' of type 
    [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting 
    bean property 'entityManager'; nested exception is 
    org.springframework.beans.factory.BeanCreationException: Error 
    creating bean with name '(inner bean)#1fdfafd2': Cannot resolve 
    reference to bean 'entityManagerFactory' while setting constructor 
    argument; nested exception is 
    org.springframework.beans.factory.BeanCreationException: Error 
    creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration$$EnhancerBySpringCGLIB$$fe46103]: No default constructor found; nested exception is java.lang.NoSuchMethodException: org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration$$EnhancerBySpringCGLIB$$fe46103.<init>()Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'fumoRepository': Cannot create inner bean '(inner bean)#1fdfafd2' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#1fdfafd2': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration$$EnhancerBySpringCGLIB$$fe46103]: No default constructor found; nested exception is java.lang.NoSuchMethodException: 
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfigurati 
    on$$EnhancerBySpringCGLIB$$fe46103.<init>()

UPD:

Answer WiPU 允许解决问题。我像这样更改了我的 registerConverters 方法:

 @Configuration
 class MyConfig extends WebMvcConfigurerAdapter  
       @Bean
       public static BeanFactoryPostProcessor 
     registerConverters(ApplicationContext context) {
        Map<String, Class<? extends CrudRepository>> converterBeans = new HashMap<>();
    converterBeans.put("firstEntity", firstEntityRepository.class);
    converterBeans.put("secondEntity", secondEntity.class);
    return factory -> {
        BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) 
        factory;
        for (val entry : converterBeans.entrySet()) {
              BeanDefinitionBuilder b =

   BeanDefinitionBuilder.genericBeanDefinition(EntityConverter.class)
                            .addPropertyReference("repository", entry.getKey().concat("Repository"))
                    ;
            beanFactory.registerBeanDefinition(entry.getKey().concat("Converter"), b.getBeanDefinition());
            factory.registerSingleton(entry.getKey()
            .concat("Converter"), new EntityConverter(
                    entry.getKey(), bean));
        }
    };

【问题讨论】:

  • 如果要进行注入的 claas 不是 jsf 转换器,那么您可以让它工作吗?

标签: spring spring-boot


【解决方案1】:

Spring 未能根据您显示的异常实例化您的存储库 Bean。

在加载所有 bean 定义但尚未实例化之后调用 BeanFactoryPostProcessor。您可以在这里找到详细信息:Link

当所有其他 bean 都已正确实例化时,您可以稍后尝试注册 bean。你可以在这里找到一些细节:Link

此时您的所有存储库都应该已正确实例化,您只需添加额外的EntityConverter

或者,如果您需要将EntityConverter 注入其他bean,您可以注册BeanDefinitons。然后 Spring 将在已经创建存储库时实例化您的 bean。 Link to JavaDoc

问候, 维普

【讨论】:

  • 非常感谢。这是工作。我在我的方法 registerConverters 和 addPropertyReference 中使用了 BeanDefinitionRegistry 到具体存储库。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-07
  • 2011-03-23
  • 2015-08-11
  • 1970-01-01
  • 2011-09-25
  • 2016-01-08
相关资源
最近更新 更多