【问题标题】:Spring : How to manage datasources created with BeanFactoryPostProcessor, at runtime?Spring:如何在运行时管理使用 BeanFactoryPostProcessor 创建的数据源?
【发布时间】:2014-12-05 11:22:57
【问题描述】:

我正在使用 Spring Data JPA 开发一个项目。

我已经设法使用 BeanFactoryPostProcessor 动态创建数据源,并在我使用 AbstractRoutingDataSource 登录时切换到所需的数据源。

现在我想在运行时做的是:

  1. 获取动态数据源的映射 BeanFactoryPostProcessor
  2. 创建新数据源
  3. 将最近创建的数据源与其他数据源一起放入地图中

springContext-jpa.xml

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
............
>
<!-- 
...
...
Spring Data JPA config 
...
...
-->

<!--    Parent abstract Datasource -->
<bean id="BasicdsCargestWeb" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="${jdbc.driverClassName}"></property>
    <property name="username" value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
</bean>

<!--  Generic Datasource   -->
<bean id="dsCargestWeb" class="com.cargest.custom.CargestRoutingDataSource">
    <property name="targetDataSources">
        <map>

        </map>
    </property>
    <property name="defaultTargetDataSource" ref="cargestnet1ds" />
</bean>

</beans>

DatasourceRegisteringBeanFactoryPostProcessor.java

@Component 
class DatasourceRegisteringBeanFactoryPostProcessor implements BeanFactoryPostProcessor { 

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {

    // this is my list of Datasources 
    List<Database> dbs = new ArrayList<Database>();

    /*
     * Hidden code, here i get my list of Datasources 
     */

    BeanDefinitionRegistry factory = (BeanDefinitionRegistry) beanFactory;
    BeanDefinitionBuilder datasourceDefinitionBuilder;

    for (Database db : dbs) {
        datasourceDefinitionBuilder = BeanDefinitionBuilder
                .childBeanDefinition("BasicdsCargestWeb") 
                .addPropertyValue("url", db.getUrl()+db.getName()+"?autoReconnect=true");

        factory.registerBeanDefinition("cargestnet"+db.getId()+"ds",
                datasourceDefinitionBuilder.getBeanDefinition());
    }


    // Configure the dataSource bean properties 
    MutablePropertyValues mpv = factory.getBeanDefinition("dsCargestWeb").getPropertyValues();

    // Here you can set the default dataSource 
    mpv.removePropertyValue("defaultTargetDataSource");
    mpv.addPropertyValue("defaultTargetDataSource", 
        new RuntimeBeanReference("cargestnet1ds")); 

    // Set the targetDataSource properties map with the list of connections 
    ManagedMap<String, RuntimeBeanReference> mm = (ManagedMap<String, RuntimeBeanReference>) mpv.getPropertyValue("targetDataSources").getValue();
    System.out.println("list size "+mm.size());

    mm.clear();

    for (Database db : dbs) {
         mm.put(db.getId().toString(), new RuntimeBeanReference("cargestnet"+db.getId()+"ds"));
    }
} 
} 

问题在于 BeanFactoryPostProcessor 类使用 ConfigurableListableBeanFactory 作为 beanFactory。

我需要从另一个类(在运行时)访问同一个 beanFactory 以修改我的数据源映射(dsCargestWeb --> targetDataSources --> 映射)。

谢谢

【问题讨论】:

    标签: java spring postgresql spring-data spring-data-jpa


    【解决方案1】:

    使用RuntimeBeanReferenceManagedSet,您可以将运行时集设置为beanDefine。这是使用这些的正确方法:

    ManagedSet<RuntimeBeanReference> processorSet = new ManagedSet<RuntimeBeanReference>();
        for (String processorBeanName : processorBeanNames) {
            processorSet.add(new RuntimeBeanReference(processorBeanName));
        }
    beanDefine.getPropertyValues().addPropertyValue(new PropertyValue(key, value));
    

    【讨论】:

      【解决方案2】:

      我认为您可以尝试以下架构:

      • 工厂bean创建DataSourceS的初始映射
      • AbstractRoutingDataSource 实现保存了DataSourceS 的映射,并最初注入了上述工厂 bean

      这样,如果你以后需要添加一个新的DataSource,你可以从AbstractRoutingDataSource实现中获取映射并直接添加到它,或者在AbstractRoutingDataSource实现中放置一个方法来添加一个新的DataSource

      作为上述的变体,您可以创建一个类似的AbstractRoutingDataSource 实现,并注入另一个bean,在其init-method 中计算DataSourceS 映射并将其存储在路由数据源中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-24
        • 2017-04-12
        • 2015-05-19
        • 2014-09-19
        • 2021-09-17
        • 2018-12-05
        • 2019-07-01
        相关资源
        最近更新 更多