首页 > 解决方案 > 动态注册bean和普通bean的区别

问题描述

我正在将 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”类型的合格 bean 可用:预计至少有 1 个有资格作为自动装配候选者的 bean。依赖注释:{}

我的理解是 Spring 应该使用我的动态注册 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;
    }
}

标签: javaspringdynamicregistryjavabeans

解决方案


推荐阅读