разница между динамическим регистровым бином и обычным бином - PullRequest
0 голосов
/ 06 октября 2018

Я интегрирую 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': неудовлетворенная зависимость, выраженная через параметр конструктора 0;Вложенное исключение - org.springframework.beans.factory.NoSuchBeanDefinitionException: нет доступного квалифицирующего компонента типа 'java.util.Set': ожидается как минимум 1 компонент, который квалифицируется как кандидат для автоматического подключения.Аннотации зависимостей: {}

Насколько я понимаю, Spring должен использовать мой динамический регистр EJB для создания EntityManager.Если я прокомментирую этот код определений динамических компонентов регистра и раскомментирую этот текущий закомментированный код (public LocalContainerEntityManagerFactoryBean entityManagerFactory0 и т. Д.), Все будет работать хорошо.Я уверен, что был вызван метод фабрики бинов (createLocalContainEM).Мне просто интересно, есть ли что-то упущенное в моем определении бина регистра?Кто-нибудь может дать какой-нибудь совет?

ссылаются на 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;
    }
}
...