2012-08-23 9 views
8

を春のBeanを作成し、既存の豆のプロパティを変更し、私はsucessfully http://blog.springsource.com/2007/01/23/dynamic-datasource-routing/記事に従うことによって、データベース接続の動的な変更を実装するために管理しました。が動的に

しかし、今の問題は、私は、レガシー・アプリケーションによって管理されている設定ファイルにデータベースURLのリストを持っている、です。

値のリスト(つまりYear2011DataSource、Year2012DataSourceなど)からそのSpringコンテキストでBeanを作成し、dataSource Beanのマップを作成したばかりの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> 
+0

は、コードの最終版を追加しました。助けをいただきありがとうございます。 – Vedran

答えて

8

この要件に適して私はカスタムBeanFactoryPostProcessorだと思う - レガシー構成で読み込み、カスタムビーンファクトリポストプロセッサにデータソースを生成します。=========

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()); 
    } 
} 
+0

これで、作成したBeanへの参照を既存の「dataSource」Beanの「targetDataSource」プロパティに設定する方法を理解する必要があります。 – Vedran

+0

すべての作業が完了し、完成したサンプルを私はそれを少しきれいにする元の質問。もう一度ありがとう!:) – Vedran

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; 
} 
+0

これらのマップのjava.util.Mapはありますか?あなたが2つではない項目(キー、値)を定義/使用しているからです... – helios

+0

はい、編集済みの回答です。実際には私はnotepad ++でコードをタイプしました:) –

+0

@helios:ありがとう:) –

1

は、私の知る限りでは、XML構成を使用して何のアウトオブボックスソリューションはありません。しかし、これを達成するための簡単な解決策は、春にFactoryBean抽象化を使用してthis answerに記載されています。

1

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

Bijuの先端に従うことで、私は次のように働いて、すべてを持っていますこの:

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

春の設定の「年ごとのデータベースのURL」セクションはもう存在しません。BeanFactoryPostProcessorにBeanが作成されます。

「データソース」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"))); 
     } 
    } 
}