Spring:如何在运行时管理使用BeanFactoryPostProcessor创建的数据源?

时间:2014-10-10 10:07:05

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

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

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

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

  1. 获取动态数据源的映射 BeanFactoryPostProcessor
  2. 创建新数据源
  3. 将最近创建的数据源与其他数据源一起放入
  4. 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 - &gt; targetDataSources - &gt; map)。

    由于

2 个答案:

答案 0 :(得分:0)

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

  • 工厂bean创建DataSourceS
  • 的初始地图
  • AbstractRoutingDataSource实现包含DataSourceS的地图,最初注入上面的工厂bean

这样,如果您以后需要添加新的DataSource,您可以从AbstractRoutingDataSource实施中获取地图并将其直接添加到地图中,或者在{{1实现添加新的AbstractRoutingDataSource

作为上述变体,您可以创建一个类似的DataSource实现,并使用它注入另一个bean,在AbstractRoutingDataSource计算init-method映射并在其中进行strores路由数据源。

答案 1 :(得分:-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));