zoukankan      html  css  js  c++  java
  • 继承Spring AbstractRoutingDataSource实现路由切换

    继承Spring AbstractRoutingDataSource实现路由切换

    原创 2016年05月11日 16:50:08

    下面是结合项目整理的如何实现Spring下数据路由动态切换,分三部分,1.配置文件。2.java类。3.总结

    一:配置文件

    dataAnt.properties:

    [html] view plain copy
     
    1. driverClass1=oracle.jdbc.driver.OracleDriver  
    2. jdbcUrl1=jdbc:oracle:thin:@136.160.40.36:1521:crmtemp  
    3. db.user1=crm_app  
    4. db.password1=abc123  
    5.   
    6. driverClass2=oracle.jdbc.driver.OracleDriver  
    7. jdbcUrl2=jdbc:oracle:thin:@136.160.40.36:1521:crmtest  
    8. db.user2=crm_app  
    9. db.password2=abc123  
    配置文件,两个jdbc的配置

    sm-spring-db.xml:

    [html] view plain copy
     
    1. <!-- dataAnt默认数据源 -->  
    2. <bean id="smDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
    3.     <property name="driverClassName" value="${driverClass1}">  
    4.     </property>  
    5.     <property name="url" value="${jdbcUrl1}">  
    6.     </property>  
    7.     <property name="username" value="${db.user1}">  
    8.     </property>  
    9.     <property name="password" value="${db.password1}">  
    10.     </property>  
    11.     <property name="accessToUnderlyingConnectionAllowed">  
    12.         <value>true</value>  
    13.     </property>  
    14. </bean>  
    15.   
    16. <!-- 数据迁移目标数据源 -->  
    17. <bean id="qyDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
    18.     <property name="driverClassName" value="${driverClass2}">  
    19.     </property>  
    20.     <property name="url" value="${jdbcUrl2}">  
    21.     </property>  
    22.     <property name="username" value="${db.user2}">  
    23.     </property>  
    24.     <property name="password" value="${db.password2}">  
    25.     </property>  
    26.     <property name="accessToUnderlyingConnectionAllowed">  
    27.         <value>true</value>  
    28.     </property>  
    29. </bean>  
    30.   
    31.   
    32. <!-- 数据路由dataSource-->  
    33. <bean id="dataSource" class="com.ai.data.common.LinkageRoutingDataSource">  
    34.     <property name="targetDataSources">  
    35.         <map key-type="java.lang.String">  
    36.             <entry value-ref="smDataSource" key="smDataSource"></entry>  
    37.             <entry value-ref="qyDataSource" key="qyDataSource"></entry>  
    38.         </map>  
    39.     </property>  
    40.     <property name="defaultTargetDataSource" ref="smDataSource"></property>      <!-- 默认使用ds1的数据源 -->  
    41. </bean>  
    1.这里,配置了两个数据源smDataSource,qyDataSource,并且通过类LinkageRoutingDataSource类实现路由切换。注意设置Bean id为dataSource,保证后面事物控制到对应数据源。

    2.bean id = 'dataSource'里注意,必须设置目标数据源targetDataSource和defaultTargetDataSource。


    注入jdbcTemplate工具类:

    [html] view plain copy
     
    1. <!--注入JdbcTemplate切换dataSource工具类[获取bean名,重设dataSource] -->  
    2.     <bean class="com.ai.data.common.JdbcTemplateUtil"></bean>  


    二:java类

    LinkageRoutingDataSource.java

    [java] view plain copy
     
    1. package com.ai.data.common;  
    2.   
    3. import org.apache.commons.lang.StringUtils;  
    4. import org.arrow.common.utils.Log;  
    5. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;  
    6.   
    7. /** 
    8.  * 设置数据源 
    9.  * 
    10.  * @author weiweiai 
    11.  * @see [相关类/方法](可选) 
    12.  * @since [产品/模块版本] (可选) 
    13.  */  
    14. public class LinkageRoutingDataSource extends AbstractRoutingDataSource {   
    15.     private static final Log log = Log.getLog(LinkageRoutingDataSource.class);  
    16.       
    17.     //目标数据源  
    18.     private static final ThreadLocal<String> TARGET_DATA_SOURCE = new ThreadLocal<String>();  
    19.     //默认数据源--指标监控的  
    20.     public static final String DEFAULT_DATA_SOURCE = "smDataSource";  
    21.       
    22.     /** 
    23.      * 根据PrvncUtil类设置进去的当前线程数据源进行数据源切换 
    24.      *  
    25.      * @param 无 
    26.      * @return 数据源名称 
    27.      */  
    28.     protected Object determineCurrentLookupKey() {  
    29.         String targetDataSource = TARGET_DATA_SOURCE.get();  
    30.         if (StringUtils.isEmpty(targetDataSource)) {  
    31.             targetDataSource = DEFAULT_DATA_SOURCE; //默认数据源为指标监控数据源  
    32.             TARGET_DATA_SOURCE.set(targetDataSource);  
    33.         }  
    34.         log.debug("当前线程数据源----------------:{}", targetDataSource);  
    35.         return targetDataSource;  
    36.     }    
    37.       
    38.     /** 
    39.      * 设置数据源名 
    40.      * @param target 
    41.      */  
    42.     public static void setTargetDataSource(String target) {  
    43.         TARGET_DATA_SOURCE.set(target);  
    44.     }  
    45.       
    46.     /** 
    47.      * 取数据源名 
    48.      * @return 
    49.      */  
    50.     public static String getTargetDataSource(){  
    51.         return TARGET_DATA_SOURCE.get();  
    52.     }  
    53.       
    54.       
    55. }  

    1.实现Spring提供的AbstractRoutingDataSource抽象类,利用ThreadLocal类型来定义TARGET_DATA_SOURCE(目标数据源),保证线程间数据源名不互相影响。

    2.指定默认数据源名,对应第一步中bean id =‘smDataSource’

    3.determineCurrentLookupKey这个方法,个人理解,如下图:意思应该是说code想建立数据源连接时候,此方法就会执行目的是找到合适数据源。

    这里代码里,就是先取TARGET_DATA_SOURCE线程变量里线程安全的TARGET_DATA_SOURCE,取不到就用默认数据源smDataSource。从而实现bean id='dataSource'属性targetDataSources切换。

    PrvncUtil.java

    [java] view plain copy
     
    1. package com.ai.data.common;  
    2.   
    3. import org.apache.commons.lang.StringUtils;  
    4. import org.arrow.common.utils.Log;  
    5.   
    6. /** 
    7.  * 设置获取当前线程数据源名称 
    8.  *  
    9.  * @date 20150924 
    10.  * @author weiweiai 
    11.  */  
    12. public class PrvncUtil {  
    13.       
    14.     private static final Log LOG_OUTPUT = Log.getLog(PrvncUtil.class);  
    15.     
    16.     //默认数据源  
    17.     public static final String DEFAULT_DATA_SOURCE = "smDataSource";  
    18.       
    19.     /** 
    20.      * 设置需要用的数据源名称 
    21.      *  
    22.      * @param dataSourceName 数据源名称 
    23.      * @retrun 无 
    24.      */  
    25.     public static void setDataSourceName(String dataSourceName) {    
    26.         LinkageRoutingDataSource.setTargetDataSource(getDataSourceName(dataSourceName));  
    27.     }    
    28.       
    29.     /** 
    30.      * 获取数据源名称 
    31.      * @param dataSourceName 
    32.      * @return 数据源名称 
    33.      */  
    34.     public static String getDataSourceName(String dataSourceName) {  
    35.         String dataSource = dataSourceName;  
    36.         if(StringUtils.isEmpty(dataSource)){  
    37.             dataSource = DEFAULT_DATA_SOURCE;  
    38.         }  
    39.         LOG_OUTPUT.debug("最终获取到的当前数据源名称:{}", dataSource);  
    40.         //((JdbcTemplate)SpringContextHolder.getBean("jdbcTemplate")).setDataSource((DataSource)SpringContextHolder.getBean(dataSource));  
    41.         return dataSource;    
    42.     }    
    43. }    
    数据路由切换工具类

    JdbcTemplateUtil.java

    [java] view plain copy
     
    1. package com.ai.data.common;  
    2.   
    3. import javax.sql.DataSource;  
    4.   
    5. import org.springframework.beans.BeansException;  
    6. import org.springframework.beans.factory.annotation.Autowired;  
    7. import org.springframework.context.ApplicationContext;  
    8. import org.springframework.context.ApplicationContextAware;  
    9. import org.springframework.jdbc.core.JdbcTemplate;  
    10. import com.linkage.bss.commons.util.StringUtil;  
    11.   
    12.   
    13. /** 
    14.  * JdbcTemplate工具类,实现切换数据源后JdbcTemplate数据源重设 
    15.  * @author weiweiai 
    16.  * 2016/5/10 
    17.  * 
    18.  */  
    19. public class JdbcTemplateUtil implements ApplicationContextAware{  
    20.   
    21.     @Autowired  
    22.     private JdbcTemplate jdbcTemplate;  
    23.       
    24.     public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {  
    25.         this.jdbcTemplate = jdbcTemplate;  
    26.     }  
    27.   
    28.     private ApplicationContext ctx;  
    29.       
    30.     /* 
    31.      * (non-Javadoc) 
    32.      * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) 
    33.      */  
    34.     public void setApplicationContext(ApplicationContext applicationContext)  
    35.             throws BeansException {  
    36.         // TODO Auto-generated method stub  
    37.         this.ctx = applicationContext;  
    38.     }  
    39.       
    40.     /* 
    41.      * 取LinkageRoutingDataSource 线程变量中数据源,重设jdbcTemplate的数据源属性 
    42.      */  
    43.     public JdbcTemplate getJdbcTemplate(){  
    44.         String ds = LinkageRoutingDataSource.getTargetDataSource();  
    45.         if(!StringUtil.isEmpty(ds))  
    46.             jdbcTemplate.setDataSource((DataSource)ctx.getBean(ds));  
    47.         return jdbcTemplate;  
    48.     }  
    49. }  
    1.实现ApplicationContextAware接口,且在第一步中已引入,作用是获取到Spring容器中注入的bean。

    2.getJdbcTemplate()方法,先获取LinkageRoutingDataSource类中TARGET_DATA_SOURCE线程变量中保存的数据源名。

    3.ds为空,返回的是默认数据源;否则切换jdbcTemplate的数据源。


    调用:

    [java] view plain copy
     
    1. PrvncUtil.setDataSourceName("qyDataSource");  
    2. primaryValueList = jdbcTemplateUtil.getJdbcTemplate().queryForList((String) dataMap.get("SELFORPRIMARY"));  



    三:总结

    [html] view plain copy
     
    1. PrvncUtil.setDataSourceName("qyDataSource");  
    实现了切换:
     


    primaryValueList = jdbcTemplateUtil.getJdbcTemplate().queryForList((String) dataMap.get("SELFORPRIMARY"));

    实现了:

    这里为什么jdbcTemplate已经指到dataSource.而dataSource也已经改变属性targetDataSource却没用,我也不懂,欢迎大神指导原因。我已经亲试,确实需要手工

    [html] view plain copy
     
    1. jdbcTemplate.setDataSource((DataSource)ctx.getBean(ds))  
    不然数据源切不过来,已验证。
  • 相关阅读:
    SharePoint网站迁移问题
    使用.NET框架自带的Json序列化类
    IL:Hello World
    Javascript面向对象
    抽象代数学习记录
    关于集成测试
    用QTP脚本操作腾讯QQ好友买卖功能
    关于白盒测试一些资料
    Developer小记
    架构设计
  • 原文地址:https://www.cnblogs.com/diegodu/p/8067231.html
Copyright © 2011-2022 走看看