8

http://blog.springsource.com/2007/01/23/dynamic-datasource-routing/の記事に従って、データベース接続の動的な変更を実装することに成功しました。

しかし今問題は、レガシーアプリケーションによって管理されている構成ファイルにデータベースのURLのリストがあることです。

値のリスト(つまり、Year2011DataSource、Year2012DataSource、...)からそのSpringコンテキストでBeanを作成し、作成されたばかりのBeanをdataSource Beanのマップに取り込む方法はありますか?

<!-- Property file located in the legacy application's folder -->
<context:property-placeholder location="file:///D:/config.properties" />

<!-- Shared data source properties are read from the config.properties file -->
<bean id="parentDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" abstract="true">
    <property name="driverClassName" value="${db.driver}" />
    <property name="username" value="${db.user}" />
    <property name="password" value="${db.password}" />
</bean>

<!-- Database urls by year -->
<bean id="Year2012DataSource" parent="parentDataSource">
    <property name="url" value="jdbc:sqlserver://localhost;databaseName=DbName_v570_2012" />
</bean>
<bean id="Year2011DataSource" parent="parentDataSource">
    <property name="url" value="jdbc:sqlserver://localhost;databaseName=DbName_v570_2011" />
</bean>
<bean id="Year2010DataSource" parent="parentDataSource">
    <property name="url" value="jdbc:sqlserver://localhost;databaseName=DbName_v570_2010" />
</bean>
<!-- ... and so on, these should instead be populated dynamically ... -->

<!-- DbConnectionRoutingDataSource extends AbstractRoutingDataSource -->
<bean id="dataSource" class="someProject.DbConnectionRoutingDataSource">
    <property name="targetDataSources">
        <map key-type="int">
            <entry key="2011" value-ref="Year2011DataSource" />
            <entry key="2010" value-ref="Year2010DataSource" />
            <!-- ... and so on, these also should instead be populated dynamically ... -->
        </map>
    </property>
    <property name="defaultTargetDataSource" ref="Year2012DataSource" />
</bean>
4

4 に答える 4

8

この要件に適しているのは、カスタムBeanFactoryPostProcessorです。レガシー構成を読み取り、カスタムBeanファクトリポストプロセッサでデータソースを生成します。

class MyDatasourceRegisteringBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        //Read in details from legacy properties.. build custom bean definitions and register with bean factory
        //for each legacy property...
            BeanDefinitionBuilder datasourceDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicDataSource.class).addPropertyValue("url", "jdbc..");
            beanFactory.registerBeanDefinition(datasourceDefinitionBuilder.getBeanDefinition());
    }
}
于 2012-08-23T13:39:34.243 に答える
1

アノテーションのアプローチを教えてあげましょう。プロパティファイルにURLと構成を追加し、次のようにします。

@Bean(name="dataSourceMap")
public Map<String, DataSource> dataSourceMap(DataSource dataSource2011, DataSource dataSource2012) {
    // read properties from properties file and create map of datasource

    Map<DataSource> map = new HashMap<>();
    map.put("dataSource2011",dataSource2011);
    map.put("dataSource2012",dataSource2012);
    //map.put("dataSource2013",dataSource2013);
    return map;
}

@Bean(name="dataSource2011",destroyMethod="close")
public DataSource dataSource() {
    // read properties from properties file and create map of 

    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setDriverClassName(driverClassName);
    dataSource.setUrl(url2011);
    dataSource.setUsername(username2011);
    dataSource.setPassword(password2011);               
    return dataSource;
}

@Bean(name="dataSource2012",destroyMethod="close")
public DataSource dataSource() {
    // read properties from properties file and create map of 

    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setDriverClassName(driverClassName);
    dataSource.setUrl(url2012);
    dataSource.setUsername(username2012);
    dataSource.setPassword(password2012);               
    return dataSource;
}
于 2012-08-23T11:33:09.827 に答える
1

私の知る限り、XML構成を使用したすぐに使用できるソリューションはありません。ただし、これを実現するための簡単なソリューションは、Springの抽象化を使用したこの回答で説明されています。FactoryBean

于 2012-08-23T11:36:50.573 に答える
1

============================================

Bijuのヒントに従うことで、すべてが次のように機能するようになります。

============================================

春の構成の「年ごとのデータベースURL」セクションはなくなり、BeanはBeanFactoryPostProcessorで作成されます。

「dataSource」Beanのプロパティは、BeanFactoryPostProcessorで置き換えられるダミーデータに設定されています。

<bean id="dataSource" class="someProject.DbConnectionRoutingDataSource">
    <property name="targetDataSources">
        <map key-type="String">
            <!-- Will be filled from the DatasourceRegisteringBeanFactoryPostProcessor -->
        </map>
    </property>
    <property name="defaultTargetDataSource" value="java:jboss/datasources/ExampleDS" />
</bean>

そして、これはBeanFactoryPostProcessorの実装です。

@Component
class DatasourceRegisteringBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        InitialContext ic = new InitialContext();

        // read the list of available JNDI connections
        NamingEnumeration<?> list = ic.listBindings(getJndiDSRoot());
        HashSet<String> jndiDataSources = new HashSet<String>();
        while (list.hasMore()) {
            /*... (ommitted for simplicity) ...*/
            connectionsList.put(key, value);
        }            

        BeanDefinitionRegistry factory = (BeanDefinitionRegistry) beanFactory;
        BeanDefinitionBuilder datasourceDefinitionBuilder;

        // Create new beans
        for (Entry<Integer, String> e : connectionsList.entrySet()) {
            datasourceDefinitionBuilder = BeanDefinitionBuilder
                    .childBeanDefinition("parentDataSource")
                    .addPropertyValue("url", e.getValue());

            factory.registerBeanDefinition("Year" + e.getKey() + "DataSource",
                    datasourceDefinitionBuilder.getBeanDefinition());
        }

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

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

        // Set the targetDataSource properties map with the list of connections
        ManagedMap<Integer, RuntimeBeanReference> mm = (ManagedMap<Integer, RuntimeBeanReference>) mpv.getPropertyValue("targetDataSources").getValue();
        mm.clear();

        // Fill the map with bean references to the newly created beans
        for (Entry<Integer, String> e : connectionsList.entrySet()) {
            mm.put(e.getKey(), new RuntimeBeanReference("Year" + e.getKey() + "DataSource")));
        }
    }
}
于 2012-08-27T08:06:25.410 に答える