Spring动态数据源路由兑现
Spring动态数据源路由实现简单的翻译, 也算是一篇笔记.?原文:http://blog.springsource.com/2007/01/23/dy
Spring动态数据源路由实现
简单的翻译, 也算是一篇笔记.?
原文:http://blog.springsource.com/2007/01/23/dynamic-datasource-routing/?
在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上, 同时对于不支持事务隔离级别的JTA事务来说, Spring还提供了另外一个类IsolationLevelDataSourceRouter来处理这个问题. 下面的例子将通过context来切换不同的数据源.?
首先定义一个Catalog的Dao:?
Java代码??
- ?package?blog.datasource;??
- ??
- import?java.sql.ResultSet;??
- import?java.sql.SQLException;??
- import?java.util.List;??
- ??
- import?org.springframework.jdbc.core.simple.ParameterizedRowMapper;??
- import?org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport;??
- ??
- public?class?Catalog?extends?SimpleJdbcDaoSupport?{??
- ??????????
- ???public?List<Item>?getItems()?{??
- ??????String?query?=?"select?name,?price?from?item";??
- ??????return?getSimpleJdbcTemplate().query(query,?new?ParameterizedRowMapper<Item>()?{??
- ????????????public?Item?mapRow(ResultSet?rs,?int?row)?throws?SQLException?{??
- ???????????????String?name?=?rs.getString(1);??
- ???????????????double?price?=?rs.getDouble(2);??
- ???????????????return?new?Item(name,?price);??
- ????????????}??
- ??????});??
- ???}??
- }??
然后定义一个Item的JavaBean?
Java代码??

- package?blog.datasource;??
- ??
- public?class?Item?{??
- ??
- ???private?String?name;??
- ???private?double?price;??
- ??????????
- ???public?Item(String?name,?double?price)?{??
- ??????this.name?=?name;??
- ??????this.price?=?price;??
- ???}??
- ??
- ???public?String?getName()?{??
- ??????return?name;??
- ???}??
- ??
- ???public?double?getPrice()?{??
- ??????return?price;??
- ???}??
- ??
- ???public?String?toString()?{??
- ??????return?name?+?"?("?+?price?+?")";??
- ???}??
- ??
- }??
接着定义一个枚举类型, 用来表示不同的用户级别, 通过该类型将映射到不同的数据源?
Java代码??

- public?enum?CustomerType?{??
- ???BRONZE,???
- ???SILVER,???
- ???GOLD??
- }??
下面是DataSource定义:?
Xml代码??

- <bean?id="parentDataSource"??
- ?????????class="org.springframework.jdbc.datasource.DriverManagerDataSource"??
- ?????????abstract="true">??
- ???<property?name="driverClassName"?value="org.hsqldb.jdbcDriver"/>??
- ???<property?name="username"?value="sa"/>??
- </bean>??
- ??????????????????
- <bean?id="goldDataSource"?parent="parentDataSource">??
- ???<property?name="url"?value="jdbc:hsqldb:hsql://localhost:${db.port.gold}/blog"/>??
- </bean>??
- ??
- <bean?id="silverDataSource"?parent="parentDataSource">??
- ???<property?name="url"?value="jdbc:hsqldb:hsql://localhost:${db.port.silver}/blog"/>??
- </bean>??
- ??
- <bean?id="bronzeDataSource"?parent="parentDataSource">??
- ???<property?name="url"?value="jdbc:hsqldb:hsql://localhost:${db.port.bronze}/blog"/>??
- </bean>??
- ??
- <bean?class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">??
- ???<property?name="location"?value="classpath:/blog/datasource/db.properties"/>??
- </bean>??
AbstractRoutingDataSource 实现类?
Java代码??

- package?blog.datasource;??
- ??
- import?org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;??
- ??
- public?class?CustomerRoutingDataSource?extends?AbstractRoutingDataSource?{??
- ??
- ???@Override??
- ???protected?Object?determineCurrentLookupKey()?{??
- ??????return?CustomerContextHolder.getCustomerType();??
- ???}??
- }??
CustomerContextHolder 是一个和LocalThread绑定的类, 定义如下:?
Java代码??

- public?class?CustomerContextHolder?{??
- ??
- ???private?static?final?ThreadLocal<CustomerType>?contextHolder?=???
- ????????????new?ThreadLocal<CustomerType>();??
- ??????????
- ???public?static?void?setCustomerType(CustomerType?customerType)?{??
- ??????Assert.notNull(customerType,?"customerType?cannot?be?null");??
- ??????contextHolder.set(customerType);??
- ???}??
- ??
- ???public?static?CustomerType?getCustomerType()?{??
- ??????return?(CustomerType)?contextHolder.get();??
- ???}??
- ??
- ???public?static?void?clearCustomerType()?{??
- ??????contextHolder.remove();??
- ???}??
- }??
将dao bean和datasource bean结合起来, 至于dao和真正的datasource如何关联这个可以根据需要指定相关的策略和规则来实现:?
Xml代码??

- <bean?id="catalog"?class="blog.datasource.Catalog">??
- ???<property?name="dataSource"?ref="dataSource"/>??
- </bean>??
- ??
- <bean?id="dataSource"?class="blog.datasource.CustomerRoutingDataSource">??
- ???<property?name="targetDataSources">??
- ??????<map?key-type="blog.datasource.CustomerType">??
- ?????????<entry?key="GOLD"?value-ref="goldDataSource"/>??
- ?????????<entry?key="SILVER"?value-ref="silverDataSource"/>??
- ??????</map>??
- ???</property>??
- ???<property?name="defaultTargetDataSource"?ref="bronzeDataSource"/>??
- </bean>??
下面通过一个TestCase来看看如何使用:?
Java代码??

- public?class?CatalogTests?extends?AbstractDependencyInjectionSpringContextTests?{??
- ??
- ???private?Catalog?catalog;??
- ??
- ???public?void?setCatalog(Catalog?catalog)?{??
- ??????this.catalog?=?catalog;??
- ???}??
- ??
- ???public?void?testDataSourceRouting()?{??
- ??????CustomerContextHolder.setCustomerType(CustomerType.GOLD);??
- ??????List<Item>?goldItems?=?catalog.getItems();??
- ??????assertEquals(3,?goldItems.size());??
- ??????System.out.println("gold?items:?"?+?goldItems);??
- ??
- ??????CustomerContextHolder.setCustomerType(CustomerType.SILVER);??
- ??????List<Item>?silverItems?=?catalog.getItems();??
- ??????assertEquals(2,?silverItems.size());??
- ??????System.out.println("silver?items:?"?+?silverItems);??
- ??????????
- ??????CustomerContextHolder.clearCustomerType();??
- ??????List<Item>?bronzeItems?=?catalog.getItems();??
- ??????assertEquals(1,?bronzeItems.size());??
- ??????System.out.println("bronze?items:?"?+?bronzeItems);????????????????
- ???}??
- ??
- ???protected?String[]?getConfigLocations()?{??
- ??????return?new?String[]?{"/blog/datasource/beans.xml"};??
- ???}??????
- } ?