动态注册bean和普通bean之间的区别

时间:2018-10-06 13:59:44

标签: java spring dynamic registry javabeans

我正在将JTA(Atomikos)与Spring Boot + Hibernate集成在一起。我想处理可变数量的数据源。以下是我的配置代码部分。

@Configuration
@ConditionalOnProperty(prefix = "spring.jta.atomikos", name = "enableAtomikosHibernateJpaConfiguration")
@EnableConfigurationProperties(JpaProperties.class)
@Order(Ordered.LOWEST_PRECEDENCE)
public class AtomikosHibernateJpaConfiguration implements InitializingBean{
private static final Log logger = LogFactory.getLog(AtomikosHibernateJpaConfiguration.class);

private BeanDefinitionRegistry beanRegistry;

@Autowired
LocalContainEMFFactory lcEEMFF;


@Autowired
BeanDefinitionRegistryProvider beanDefinitionRegistryProvider;

@Autowired 
List<DataSource> dataSources;
@Autowired
List<ScanPackageProperties> scanPackageProperties;
@Autowired
JpaProperties properties;

@Autowired 
private JtaTransactionManager jtaTransactionManager;

public AtomikosHibernateJpaConfiguration() {
}

@Override
public void afterPropertiesSet() throws Exception {
    beanRegistry = beanDefinitionRegistryProvider.getBeanDefReg();
    int i = 0;
    for(DataSource ds : dataSources) {
        String beanName = "entityManagerFactory" + i;
        BeanDefinitionBuilder builder = BeanDefinitionBuilder
                                            .genericBeanDefinition(AbstractEntityManagerFactoryBean.class);
        builder.setFactoryMethodOnBean("createLocalContainEM", "LocalContainEMFFactory");
        builder.addConstructorArgValue(ds);
        builder.addConstructorArgValue(properties);
        builder.addConstructorArgValue(scanPackageProperties.get(i).getPac());
        builder.addConstructorArgValue(getJtaTransactionManager());
        builder.setAutowireMode(3);
        beanRegistry.registerBeanDefinition(beanName, builder.getBeanDefinition());
        //BeanDefinition newBeanDef = beanRegistry.getBeanDefinition(beanName);
        //((ConfigurableListableBeanFactory) beanRegistry).initializeBean(newBeanDef, beanName);
        //((ConfigurableListableBeanFactory) beanRegistry).autowireBean(newBeanDef);

        i++;
    }
}

//  @Bean
//  public LocalContainerEntityManagerFactoryBean entityManagerFactory0(@Qualifier("dataSourceOne") DataSource dataSource 
//        , JpaProperties properties
//        ) {
//      EntityManagerFactoryBuilder factoryBuilder = new EntityManagerFactoryBuilder(
//                                      new HibernateJpaVendorAdapter(), new HashMap(),
//                                      null);
//      
//      Map<String, Object> vendorProperties = lcEEMFF.getVendorProperties(properties);
//      lcEEMFF.customizeVendorProperties(vendorProperties, jtaTransactionManager);
//      return factoryBuilder.dataSource(dataSource).packages("sample.atomikos")
//                  .properties(vendorProperties)
//                  .jta(true).build();
//  
//  }
//  @Bean
//  public LocalContainerEntityManagerFactoryBean entityManagerFactory1(@Qualifier("dataSourceTwo") DataSource dataSource, JpaProperties properties) {
//      EntityManagerFactoryBuilder factoryBuilder = new EntityManagerFactoryBuilder(
//                  new HibernateJpaVendorAdapter(), new HashMap(),
//                  null);
//
//      Map<String, Object> vendorProperties = lcEEMFF.getVendorProperties(properties);
//      lcEEMFF.customizeVendorProperties(vendorProperties, jtaTransactionManager);
//      return factoryBuilder.dataSource(dataSource).packages("sample.atomikos2.repo2")
//                      .properties(vendorProperties)
//                      .jta(true).build();
//    }
...

此代码将导致失败并显示以下消息:

  

创建名称为'jpaContext'的bean时出错:不满意的依赖关系   通过构造函数参数0表示;嵌套异常为   org.springframework.beans.factory.NoSuchBeanDefinitionException:否   类型的合格豆   'java.util.Set'可用:预期   至少1个符合自动装配候选条件的bean。相依性   注释:{}

我的理解是Spring应该使用我的dynamice注册bean创建EntityManager。如果我注释了动态寄存器bean定义的那些代码,并且取消注释了这些当前注释的代码(public LocalContainerEntityManagerFactoryBean entityManagerFactory0等),那么一切正常。我确定这些bean工厂方法(createLocalContainEM)被调用了。我只是想知道我的注册bean定义中缺少什么吗?有人可以给些建议吗?

引用的LocalContainEMFFactory和BeanDefinitionRegistryProvider如下。

@Component("LocalContainEMFFactory")
public class LocalContainEMFFactory{

    String JTA_PLATFORM = "hibernate.transaction.jta.platform";

    public LocalContainerEntityManagerFactoryBean 
            createLocalContainEM(DataSource dataSource 
                            , JpaProperties properties, 
                            String scanPackage,
                            JtaTransactionManager jtaTransactionManager) {
        EntityManagerFactoryBuilder factoryBuilder = new EntityManagerFactoryBuilder(
                new HibernateJpaVendorAdapter(), new HashMap(),
                null);

        Map<String, Object> vendorProperties = getVendorProperties(properties);
        customizeVendorProperties(vendorProperties, jtaTransactionManager);
        return factoryBuilder.dataSource(dataSource).packages(scanPackage)
                    .properties(vendorProperties)
                    .jta(true).build();
    }
...
}

@Component
public class BeanDefinitionRegistryProvider implements BeanFactoryPostProcessor{

    BeanDefinitionRegistry beanDefReg;

    public BeanDefinitionRegistry getBeanDefReg() {
        return beanDefReg;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        beanDefReg = (BeanDefinitionRegistry) beanFactory;
    }

}
@Component
public class ApplicationContextProvider implements ApplicationContextAware {

    private static ApplicationContext applicationContext;   

    @Autowired
    BeanDefinitionRegistryProvider beanDefinitionRegistryProvider;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextProvider.applicationContext = applicationContext;

        BeanDefinitionRegistry beanRegistry = beanDefinitionRegistryProvider.getBeanDefReg();
        for(int i = 0; i<2;  i++) {
            String beanName = "entityManagerFactory" + i;
            Object newBeanDef = applicationContext.getBean(beanName);
    //          ((ConfigurableListableBeanFactory) beanRegistry).initializeBean(newBeanDef, beanName);
            ((ConfigurableListableBeanFactory) beanRegistry).autowireBean(newBeanDef);
        }
    }

    public static final ApplicationContext getApplicationContext(){
        return applicationContext;
    }
}

0 个答案:

没有答案