我正在将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;
}
}