java - 动态注册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;
}
}
解决方案
推荐阅读
- reactjs - 将 GraphQL-AppSync-Schema-Resolver 代码与 UI ReactJS 代码分开
- jquery - 带有淡入淡出的视频文本覆盖在 Sarari 和 IE 上不起作用
- python - Flask-Admin 视图未显示 backref 列
- google-cloud-firestore - Firestore 安全规则和 Api Key
- python - 当我很确定某个值不在索引中时,Pandas .loc 说它是
- javascript - 如何通过动态构建多维数组进行搜索/过滤/类型匹配
- php - 无法使用 post 方法发送数组并将多个项目查询到 DB
- excel - 根据单元格值选择特定列
- arrays - 使用索引返回多个字符串值,匹配多个条件
- c - 连接两个捕获组