Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
84 views
in Technique[技术] by (71.8m points)

java - dynamically change Spring data source

I have a Spring application, i want to change the data source dynamically,ie. when input a DS URL, the Spring beans and all dependency will get updated automatically.I know this is somewhat strange, but anyway i want to achieve that. My Spring configuration as following:

<bean id="majorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
    <property name="serverName" value="${jdbc.serverName}" />
    <property name="portNumber" value="${jdbc.portNumber}" />
    <property name="user" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <property name="databaseName" value="${jdbc.databaseName}" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="majorDataSource"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="majorDataSource"/>
    <property name="configLocation" value="classpath:sqlmap-config.xml"/>
</bean>

The questions are:

  1. The JDBC URL is stored in properties, which could be changed runtime.

  2. Once the URL is changed, i need to re-create the data source and maybe the dependent objects. I could not figure out how to do it elegantly in Spring?

I have known that Spring did could dynamically route data source based on one key, but the data source URL is predefined in Spring and will not change runtime. It is not my case.

question from:https://stackoverflow.com/questions/13507522/dynamically-change-spring-data-source

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can use spring's AbstractRoutingDataSource by extending it and overriding the method determineCurrentLookupKey() that should return the key referencing the datasource's spring bean to be used.

Take a look at this blog article on spring source's blog which will show you an example of how to use that feature.

Basically to answer your questions, what you will need to do is to define the two datasources as different spring bean in your XML config. There is no need to create one dynamically, spring will load both, and use one or the other dynamically depending on your criteria in the determineCurrentLookupKey() method.

This would lead to something like:

XML config

<!-- first data source -->
<bean id="majorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
    <property name="serverName" value="${jdbc.major.serverName}" />
    <property name="portNumber" value="${jdbc.major.portNumber}" />
    <property name="user" value="${jdbc.major.username}" />
    <property name="password" value="${jdbc.major.password}" />
    <property name="databaseName" value="${jdbc.major.databaseName}" />
</bean>
<!-- second data source -->
<bean id="minorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
    <property name="serverName" value="${jdbc.minor.serverName}" />
    <property name="portNumber" value="${jdbc.minor.portNumber}" />
    <property name="user" value="${jdbc.minor.username}" />
    <property name="password" value="${jdbc.minor.password}" />
    <property name="databaseName" value="${jdbc.minor.databaseName}" />
</bean>
<!-- facade data source -->
<bean id="dataSource" class="blog.datasource.CustomerRoutingDataSource">
   <property name="targetDataSources">
      <map>
         <entry key="MINOR" value-ref="minorDataSource"/>
         <entry key="MAJOR" value-ref="majorDataSource"/>
      </map>
   </property>
   <property name="defaultTargetDataSource" ref="majorDataSource"/>
</bean>
<!-- wiring up -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:sqlmap-config.xml"/>
</bean>

Java

public class MyRoutingDataSource extends AbstractRoutingDataSource {
   @Override
   protected Object determineCurrentLookupKey() {
      // get the current url
      HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
      if (request.getRequestURL().toString().endsWith("/minor"))
          return "MINOR";
      else
          return "MAJOR";
   }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...