spring动态创建,加载,使用多数据源

http://blog.csdn.net/qilin18/article/details/17614005

 

 

项目中我们经常会遇到多数据源的问题,尤其是数据同步或定时任务等项目更是如此。多数据源让人最头痛的,不是配置多个数据源,而是如何能灵活动态的切换数据源。例如在一个spring和hibernate的框架的项目中,我们在spring配置中往往是配置一个dataSource来连接数据库,然后绑定给sessionFactory,在dao层代码中再指定sessionFactory来进行数据库操作。

 

正如上图所示,每一块都是指定绑死的,如果是多个数据源,也只能是下图中那种方式。

可看出在Dao层代码中写死了两个SessionFactory,这样日后如果再多一个数据源,还要改代码添加一个SessionFactory,显然这并不符合开闭原则。

那么正确的做法应该是

先说一下我的思路:

首先做一个创建数据源配置文件的类,专门用于创建数据源xml配置,叫ConfigFileCreator.java 

其次,编写一个动态加载刚才创建的配置文件的类,叫 DynamicLoadBean.java。至此,创建的数据源到内存中已经完成。

第三,重点编写这个DynamicDataSource.java,该类主要是用来实现动态切换数据源,并通知容器。在这一块我选择了修改,AbstractRoutingDataSource.java,编写一个支持添加数据源对象的方法public void addDataSource(Object key,Object dataSource)

第四,写例子来测试

实现过程如下:

1.bean.xml配置文件

 

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xmlns:tx="http://www.springframework.org/schema/tx"  
  5.     xmlns:context="http://www.springframework.org/schema/context"  
  6.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  7.                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd  
  8.                 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">  
  9.     <!-- 自动扫描与装配bean -->  
  10.     <context:component-scan base-package="qilin"></context:component-scan>  
  11.     <!-- 使用外部的配置文件 -->  
  12.     <context:property-placeholder location="classpath:jdbc.properties" />  
  13.     <bean id="defaultDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  
  14.                 <!-- 数据库连接信息 -->  
  15.                 <property name="jdbcUrl" value="${jdbcUrl}"></property>  
  16.                 <property name="driverClass" value="${driverClass}"></property>  
  17.                 <property name="user" value="${username}"></property>  
  18.                 <property name="password" value="${password}"></property>  
  19.     </bean>  
  20.       
  21.     <bean id="dataSourceA" class="com.mchange.v2.c3p0.ComboPooledDataSource">  
  22.                 <!-- 数据库连接信息 -->  
  23.                 <property name="jdbcUrl" value="jdbc:mysql:///dynamictest"></property>  
  24.                 <property name="driverClass" value="${driverClass}"></property>  
  25.                 <property name="user" value="${username}"></property>  
  26.                 <property name="password" value="${password}"></property>  
  27.     </bean>  
  28.     <bean id="dynamicdatasource" class="qilin.utils.DynamicDataSource">  
  29.         <property name="targetDataSources">  
  30.             <map key-type="java.lang.String">  
  31.                  <entry key="defaultDataSource" value-ref="defaultDataSource" />   
  32.                  <entry key="dataSourceA" value-ref="dataSourceA" />   
  33.             </map>  
  34.         </property>  
  35.         <property name="defaultTargetDataSource" ref="defaultDataSource" />  
  36.     </bean>  
  37.   
  38.     <!-- 配置SessionFactory -->  
  39.     <bean id="sessionFactory"  
  40.         class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">  
  41.         <property name="dataSource" ref="dynamicdatasource" />  
  42.         <property name="hibernateProperties">  
  43.             <props>  
  44.                 <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>  
  45.                 <prop key="hibernate.hbm2ddl.auto">none</prop>  
  46.                 <prop key="hibernate.show_sql">true</prop>  
  47.                 <prop key="hibernate.format_sql">false</prop>  
  48.                 <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>  
  49.             </props>  
  50.         </property>  
  51.         <!-- 注解方式配置 -->  
  52.         <property name="annotatedClasses">  
  53.             <list>  
  54.                 <value>qilin.entity.Student</value>  
  55.             </list>  
  56.         </property>  
  57.     </bean>  
  58.   
  59.   
  60.     <!-- 配置声明式事务管理,采用基于注解的方式 -->  
  61.     <bean id="transactionManager"  
  62.         class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
  63.         <property name="sessionFactory" ref="sessionFactory"></property>  
  64.     </bean>  
  65.     <tx:annotation-driven transaction-manager="transactionManager" />  
  66.     <bean id="dynamicLoadBean" class="qilin.utils.DynamicLoadBean"></bean>  
  67. </beans>  

2.AbstractRoutingDataSource.class 修改的部分

 

 

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. /**@author qilin**/  
  2.     public void addDataSource(Object key,Object dataSource){  
  3.           
  4.         this.targetDataSources.put(key, dataSource);  
  5.           
  6.         setTargetDataSources(this.targetDataSources);  
  7.     }  

3.DynamicDataSource.class  这个类中有一个地方需要注意,当我们添加数据,切换了数据源,要通知当前spring容器,需要调用父类的super.afterPropertiesSet();方法

 

 

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. package qilin.utils;  
  2.   
  3. import java.util.Map;  
  4.   
  5. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;  
  6. import org.springframework.jdbc.datasource.lookup.DataSourceLookup;  
  7.   
  8. public class DynamicDataSource extends AbstractRoutingDataSource {  
  9.   
  10.     /*  
  11.      * 该方法必须要重写  方法是为了根据数据库标示符取得当前的数据库 
  12.      */  
  13.     @Override  
  14.     public Object determineCurrentLookupKey() {  
  15.         return DataSourceContextHolder.getDataSourceName();  
  16.     }  
  17.   
  18.     @Override  
  19.     public void setDataSourceLookup(DataSourceLookup dataSourceLookup) {  
  20.         super.setDataSourceLookup(dataSourceLookup);  
  21.     }  
  22.   
  23.     @Override  
  24.     public void setDefaultTargetDataSource(Object defaultTargetDataSource) {  
  25.         super.setDefaultTargetDataSource(defaultTargetDataSource);  
  26.     }  
  27.   
  28.     @Override  
  29.     public void setTargetDataSources(Map targetDataSources) {  
  30.         super.setTargetDataSources(targetDataSources);  
  31.         //重点  
  32.         super.afterPropertiesSet();  
  33.     }  
  34.   
  35. }  

4.动态加载数据源配置文件DynamicLoadBean.class

 

 

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. package qilin.utils;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.springframework.beans.BeansException;  
  6. import org.springframework.beans.factory.config.BeanDefinition;  
  7. import org.springframework.beans.factory.support.BeanDefinitionRegistry;  
  8. import org.springframework.beans.factory.support.ChildBeanDefinition;  
  9. import org.springframework.beans.factory.support.DefaultListableBeanFactory;  
  10. import org.springframework.beans.factory.xml.ResourceEntityResolver;  
  11. import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;  
  12. import org.springframework.context.ApplicationContext;  
  13. import org.springframework.context.ApplicationContextAware;  
  14. import org.springframework.context.ConfigurableApplicationContext;  
  15.   
  16. /** 
  17.  * 动�?�加载数据源 
  18.  * @author qilin 
  19.  * 
  20.  */  
  21. public class DynamicLoadBean implements ApplicationContextAware {  
  22.   
  23.     private ConfigurableApplicationContext applicationContext = null;  
  24.     public void setApplicationContext(ApplicationContext applicationContext)  
  25.             throws BeansException {  
  26.   
  27.             this.applicationContext = (ConfigurableApplicationContext) applicationContext;  
  28.     }  
  29.   
  30.     public ConfigurableApplicationContext getApplicationContext() {    
  31.         return applicationContext;    
  32.     }  
  33.       
  34.     /** 
  35.      * 1.配置文件的位置固�? 
  36.      * 2.配置文件中bean的名字已�? 
  37.      * @param configLocationString 
  38.      */  
  39.      public void loadBean(String fileName)  
  40.         {    
  41.             XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader((BeanDefinitionRegistry)getApplicationContext().getBeanFactory());    
  42.             beanDefinitionReader.setResourceLoader(getApplicationContext());    
  43.             beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(getApplicationContext()));    
  44.             try  
  45.             {    
  46.                 beanDefinitionReader.loadBeanDefinitions(getApplicationContext().getResources(fileName));    
  47.             } catch (BeansException e) {    
  48.                 e.printStackTrace();    
  49.             } catch (IOException e) {    
  50.                 e.printStackTrace();    
  51.             }    
  52.         }    
  53.   
  54.      public void registBean(String beanName, String parentName) {  
  55.          DefaultListableBeanFactory  fcy = (DefaultListableBeanFactory)applicationContext.getAutowireCapableBeanFactory();  
  56.          BeanDefinition beanDefinition  = new ChildBeanDefinition(parentName);  
  57.          fcy.registerBeanDefinition(beanName, beanDefinition);  
  58.      }  
  59. }  

5.DataSourceContextHolder.class

 

 

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. package qilin.utils;  
  2.   
  3.   
  4. public class DataSourceContextHolder {  
  5.   
  6.     private static final ThreadLocal contextHolder=new ThreadLocal();  
  7.       
  8.     public static void setDataSourceType(String dataSourceName){  
  9.         contextHolder.set(dataSourceName);  
  10.     }  
  11.       
  12.     public static String getDataSourceName(){  
  13.         return (String) contextHolder.get();  
  14.     }  
  15.       
  16.     public static void clearDataSourceType(){  
  17.         contextHolder.remove();  
  18.     }  
  19.       
  20. }  

5.测试代码

 

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. package junit;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. import org.springframework.context.ApplicationContext;  
  7. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  8.   
  9. import com.mchange.v2.c3p0.ComboPooledDataSource;  
  10.   
  11. import qilin.entity.Student;  
  12. import qilin.service.StuService;  
  13. import qilin.utils.DataSourceContextHolder;  
  14. import qilin.utils.DynamicDataSource;  
  15. import qilin.utils.DynamicLoadBean;  
  16.   
  17. public class Test {  
  18.     public static void main(String[] args) {  
  19.         ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");  
  20.           
  21.         StuService stuService = (StuService) ac.getBean("stuServiceImpl");  
  22.           
  23.         Student stu = new Student();  
  24.           
  25.         stu.setStuName("qilin");  
  26.           
  27.         stuService.save(stu);  
  28.           
  29.         DataSourceContextHolder.setDataSourceType("dataSourceA");  
  30.           
  31.           
  32.         Student _stu = new Student();  
  33.           
  34.         _stu.setStuName("_qilin1");  
  35.           
  36.         stuService.save(_stu);  
  37.           
  38.         //创建一个数据源  
  39.         DynamicLoadBean dynamicBeanLoad =(DynamicLoadBean)ac.getBean("dynamicLoadBean");     
  40.         dynamicBeanLoad.loadBean("classpath:mos/qqq.xml");   
  41.         ComboPooledDataSource dataSource = (ComboPooledDataSource) ac.getBean("qqq");  
  42.         System.err.println(dataSource.getDriverClass());  
  43.           
  44.           
  45.           
  46.         DynamicDataSource dynamicDataSource = (DynamicDataSource) ac.getBean("dynamicdatasource");  
  47.          
  48. //        Map<String, ComboPooledDataSource> targetDataSources = new HashMap<String, ComboPooledDataSource>();  
  49.           
  50. //        targetDataSources.put("qqq", dataSource);  
  51.           
  52. //        Map<Object, Object> targetDataSources = dynamicDataSource.getTargetDataSources();  
  53.           
  54. //        targetDataSources.put("qqq", dataSource);  
  55.           
  56. //        dynamicDataSource.setTargetDataSources(targetDataSources);  
  57.           
  58. //        dynamicDataSource.setDefaultTargetDataSource(dataSource);  
  59.           
  60.         dynamicDataSource.addDataSource("qqq", dataSource);  
  61.           
  62.         DataSourceContextHolder.setDataSourceType("qqq");  
  63.           
  64.         Student __stu = new Student();  
  65.           
  66.         __stu.setStuName("qilin2");  
  67.           
  68.         stuService.save(__stu);  
  69.           
  70.     }  
  71. }  



 

切换数据源就一句话搞定  DataSourceContextHolder.setDataSourceType("qqq");

下载链接http://download.csdn.net/detail/qi_lin70/6778247

 

猜你喜欢

转载自gcc2ge.iteye.com/blog/2227203