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代码   收藏代码
  1.  package blog.datasource;  
  2.   
  3. import java.sql.ResultSet;  
  4. import java.sql.SQLException;  
  5. import java.util.List;  
  6.   
  7. import org.springframework.jdbc.core.simple.ParameterizedRowMapper;  
  8. import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport;  
  9.   
  10. public class Catalog extends SimpleJdbcDaoSupport {  
  11.           
  12.    public List<Item> getItems() {  
  13.       String query = "select name, price from item";  
  14.       return getSimpleJdbcTemplate().query(query, new ParameterizedRowMapper<Item>() {  
  15.             public Item mapRow(ResultSet rs, int row) throws SQLException {  
  16.                String name = rs.getString(1);  
  17.                double price = rs.getDouble(2);  
  18.                return new Item(name, price);  
  19.             }  
  20.       });  
  21.    }  
  22. }  


然后定义一个Item的JavaBean 
Java代码   收藏代码
  1. package blog.datasource;  
  2.   
  3. public class Item {  
  4.   
  5.    private String name;  
  6.    private double price;  
  7.           
  8.    public Item(String name, double price) {  
  9.       this.name = name;  
  10.       this.price = price;  
  11.    }  
  12.   
  13.    public String getName() {  
  14.       return name;  
  15.    }  
  16.   
  17.    public double getPrice() {  
  18.       return price;  
  19.    }  
  20.   
  21.    public String toString() {  
  22.       return name + " (" + price + ")";  
  23.    }  
  24.   
  25. }  


接着定义一个枚举类型, 用来表示不同的用户级别, 通过该类型将映射到不同的数据源 
Java代码   收藏代码
  1. public enum CustomerType {  
  2.    BRONZE,   
  3.    SILVER,   
  4.    GOLD  
  5. }  


下面是DataSource定义: 
Xml代码   收藏代码
  1. <bean id="parentDataSource"  
  2.          class="org.springframework.jdbc.datasource.DriverManagerDataSource"  
  3.          abstract="true">  
  4.    <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>  
  5.    <property name="username" value="sa"/>  
  6. </bean>  
  7.                   
  8. <bean id="goldDataSource" parent="parentDataSource">  
  9.    <property name="url" value="jdbc:hsqldb:hsql://localhost:${db.port.gold}/blog"/>  
  10. </bean>  
  11.   
  12. <bean id="silverDataSource" parent="parentDataSource">  
  13.    <property name="url" value="jdbc:hsqldb:hsql://localhost:${db.port.silver}/blog"/>  
  14. </bean>  
  15.   
  16. <bean id="bronzeDataSource" parent="parentDataSource">  
  17.    <property name="url" value="jdbc:hsqldb:hsql://localhost:${db.port.bronze}/blog"/>  
  18. </bean>  
  19.   
  20. <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
  21.    <property name="location" value="classpath:/blog/datasource/db.properties"/>  
  22. </bean>  


AbstractRoutingDataSource 实现类 
Java代码   收藏代码
  1. package blog.datasource;  
  2.   
  3. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;  
  4.   
  5. public class CustomerRoutingDataSource extends AbstractRoutingDataSource {  
  6.   
  7.    @Override  
  8.    protected Object determineCurrentLookupKey() {  
  9.       return CustomerContextHolder.getCustomerType();  
  10.    }  
  11. }  


CustomerContextHolder 是一个和LocalThread绑定的类, 定义如下: 
Java代码   收藏代码
  1. public class CustomerContextHolder {  
  2.   
  3.    private static final ThreadLocal<CustomerType> contextHolder =   
  4.             new ThreadLocal<CustomerType>();  
  5.           
  6.    public static void setCustomerType(CustomerType customerType) {  
  7.       Assert.notNull(customerType, "customerType cannot be null");  
  8.       contextHolder.set(customerType);  
  9.    }  
  10.   
  11.    public static CustomerType getCustomerType() {  
  12.       return (CustomerType) contextHolder.get();  
  13.    }  
  14.   
  15.    public static void clearCustomerType() {  
  16.       contextHolder.remove();  
  17.    }  
  18. }  


将dao bean和datasource bean结合起来, 至于dao和真正的datasource如何关联这个可以根据需要指定相关的策略和规则来实现: 
Xml代码   收藏代码
  1. <bean id="catalog" class="blog.datasource.Catalog">  
  2.    <property name="dataSource" ref="dataSource"/>  
  3. </bean>  
  4.   
  5. <bean id="dataSource" class="blog.datasource.CustomerRoutingDataSource">  
  6.    <property name="targetDataSources">  
  7.       <map key-type="blog.datasource.CustomerType">  
  8.          <entry key="GOLD" value-ref="goldDataSource"/>  
  9.          <entry key="SILVER" value-ref="silverDataSource"/>  
  10.       </map>  
  11.    </property>  
  12.    <property name="defaultTargetDataSource" ref="bronzeDataSource"/>  
  13. </bean>  

下面通过一个TestCase来看看如何使用: 
Java代码   收藏代码
  1. public class CatalogTests extends AbstractDependencyInjectionSpringContextTests {  
  2.   
  3.    private Catalog catalog;  
  4.   
  5.    public void setCatalog(Catalog catalog) {  
  6.       this.catalog = catalog;  
  7.    }  
  8.   
  9.    public void testDataSourceRouting() {  
  10.       CustomerContextHolder.setCustomerType(CustomerType.GOLD);  
  11.       List<Item> goldItems = catalog.getItems();  
  12.       assertEquals(3, goldItems.size());  
  13.       System.out.println("gold items: " + goldItems);  
  14.   
  15.       CustomerContextHolder.setCustomerType(CustomerType.SILVER);  
  16.       List<Item> silverItems = catalog.getItems();  
  17.       assertEquals(2, silverItems.size());  
  18.       System.out.println("silver items: " + silverItems);  
  19.           
  20.       CustomerContextHolder.clearCustomerType();  
  21.       List<Item> bronzeItems = catalog.getItems();  
  22.       assertEquals(1, bronzeItems.size());  
  23.       System.out.println("bronze items: " + bronzeItems);                
  24.    }  
  25.   
  26.    protected String[] getConfigLocations() {  
  27.       return new String[] {"/blog/datasource/beans.xml"};  
  28.    }      
  29. }  

猜你喜欢

转载自lzy83925.iteye.com/blog/1150209