Druid动态数据源配置
上文已经讲了单个数据源的Druid的配置(http://www.cnblogs.com/nbfujx/p/7686634.html)
Druid动态数据源配置 主要是继承AbstractRoutingDataSource再通过AOP来实现动态数据源切换
Druid动态数据源的使用(基于原先的程序调整)
使用步骤:
1.调整配置属性文件:mybatis.properties (增加DataSource连接参数)
1 master.driver=com.mysql.jdbc.Driver 2 master.url=jdbc:mysql://127.0.0.1:3306/jawavesys 3 master.username=root 4 master.password=jawave88 5 #定义初始连接数 6 master.initialSize=0 7 #定义最大连接数 8 master.maxActive=20 9 #定义最大空闲 10 master.maxIdle=20 11 #定义最小空闲 12 master.minIdle=1 13 #定义最长等待时间 14 master.maxWait=60000 15 16 17 slave.driver=com.mysql.jdbc.Driver 18 slave.url=jdbc:mysql://127.0.0.1:3306/jawave_eform 19 slave.username=root 20 slave.password=jawave88 21 #定义初始连接数 22 slave.initialSize=0 23 #定义最大连接数 24 slave.maxActive=20 25 #定义最大空闲 26 slave.maxIdle=20 27 #定义最小空闲 28 slave.minIdle=1 29 #定义最长等待时间 30 slave.maxWait=60000
2.调整SPRING配置文件:spring-base.xml
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" xmlns:p="http://www.springframework.org/schema/p" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" 6 xmlns:aop="http://www.springframework.org/schema/aop" 7 xsi:schemaLocation="http://www.springframework.org/schema/beans 8 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 9 http://www.springframework.org/schema/context 10 http://www.springframework.org/schema/context/spring-context-3.1.xsd 11 http://www.springframework.org/schema/tx 12 http://www.springframework.org/schema/tx/spring-tx-3.1.xsd 13 http://www.springframework.org/schema/aop 14 http://www.springframework.org/schema/aop/spring-aop-3.1.xsd 15 http://www.springframework.org/schema/mvc 16 http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> 17 18 19 <context:component-scan base-package="com.goku.druid.demo"> 20 <context:exclude-filter type="annotation" 21 expression="org.springframework.stereotype.Controller" /> 22 </context:component-scan> 23 24 <!-- 引入配置文件 --> 25 <bean id="propertyConfigurer" 26 class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 27 <property name="location" value="classpath:mybatis.properties" /> 28 </bean> 29 30 <bean id="masterDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> 31 <property name="driverClassName" value="${master.driver}" /> 32 <property name="url" value="${master.url}" /> 33 <property name="username" value="${master.username}" /> 34 <property name="password" value="${master.password}" /> 35 <!-- 初始化连接大小 --> 36 <property name="initialSize" value="${master.initialSize}"></property> 37 <!-- 连接池最大数量 --> 38 <property name="maxActive" value="${master.maxActive}"></property> 39 <!-- 连接池最大空闲 --> 40 <property name="maxIdle" value="${master.maxIdle}"></property> 41 <!-- 连接池最小空闲 --> 42 <property name="minIdle" value="${master.minIdle}"></property> 43 <!-- 获取连接最大等待时间 --> 44 <property name="maxWait" value="${master.maxWait}"></property> 45 <!-- 这里配置提交方式,默认就是TRUE,可以不用配置 --> 46 <property name="defaultAutoCommit" value="true" /> 47 <!-- 验证连接有效与否的SQL,不同的数据配置不同 --> 48 <property name="validationQuery" value="select 1 " /> 49 <!--通过别名的方式配置扩展插件,监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall--> 50 <property name="filters" value="stat,log4j" /> 51 <property name="proxyFilters"> 52 <list> 53 <ref bean="stat-filter" /> 54 <ref bean="log-filter"/> 55 </list> 56 </property> 57 </bean> 58 59 <bean id="slaveDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> 60 <property name="driverClassName" value="${slave.driver}" /> 61 <property name="url" value="${slave.url}" /> 62 <property name="username" value="${slave.username}" /> 63 <property name="password" value="${slave.password}" /> 64 <!-- 初始化连接大小 --> 65 <property name="initialSize" value="${slave.initialSize}"></property> 66 <!-- 连接池最大数量 --> 67 <property name="maxActive" value="${slave.maxActive}"></property> 68 <!-- 连接池最大空闲 --> 69 <property name="maxIdle" value="${slave.maxIdle}"></property> 70 <!-- 连接池最小空闲 --> 71 <property name="minIdle" value="${slave.minIdle}"></property> 72 <!-- 获取连接最大等待时间 --> 73 <property name="maxWait" value="${slave.maxWait}"></property> 74 <!-- 这里配置提交方式,默认就是TRUE,可以不用配置 --> 75 <property name="defaultAutoCommit" value="true" /> 76 <!-- 验证连接有效与否的SQL,不同的数据配置不同 --> 77 <property name="validationQuery" value="select 1 " /> 78 <!--通过别名的方式配置扩展插件,监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall--> 79 <property name="filters" value="stat,log4j" /> 80 <property name="proxyFilters"> 81 <list> 82 <ref bean="stat-filter" /> 83 <ref bean="log-filter"/> 84 </list> 85 </property> 86 </bean> 87 88 <bean id="dataSource" class="com.goku.druid.demo.util.DynamicDataSource"> 89 <property name="targetDataSources"> 90 <map key-type="java.lang.String"> 91 <!-- master --> 92 <entry key="master" value-ref="masterDataSource"/> 93 <!-- slave --> 94 <entry key="slave" value-ref="slaveDataSource"/> 95 </map> 96 </property> 97 <property name="defaultTargetDataSource" ref="masterDataSource"/> 98 </bean> 99 100 <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 --> 101 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 102 <property name="dataSource" ref="dataSource" /> 103 <!-- 自动扫描mapping.xml文件 --> 104 <property name="mapperLocations" value="classpath:mapping/**/*.xml"></property> 105 </bean> 106 107 <!-- DAO接口所在包名,Spring会自动查找其下的类 --> 108 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 109 <property name="basePackage" value="com.goku.druid.demo.mapper" /> 110 <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> 111 </bean> 112 113 <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx --> 114 <bean id="transactionManager" 115 class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 116 <property name="dataSource" ref="dataSource" /> 117 </bean> 118 119 <!-- 开启事务注解驱动 --> 120 <tx:annotation-driven transaction-manager="transactionManager"/> 121 122 <!-- 为业务逻辑层的方法解析@DataSource注解 为当前线程的routeholder注入数据源key --> 123 <bean id="dataSourceAspect" class="com.goku.druid.demo.util.DataSourceAspect" /> 124 <aop:config proxy-target-class="true"> 125 <aop:aspect id="dataSourceAspect" ref="dataSourceAspect" order="1"> 126 <aop:pointcut id="tx" expression="execution(* com.goku.druid.demo.service..*.*(..)) "/> 127 <aop:before pointcut-ref="tx" method="before" /> 128 </aop:aspect> 129 </aop:config> 130 131 <!--监控统计--> 132 <bean id="stat-filter" class="com.alibaba.druid.filter.stat.StatFilter"> 133 <property name="slowSqlMillis" value="10000" /> 134 <property name="logSlowSql" value="true" /> 135 </bean> 136 137 <!--日志--> 138 <bean id="log-filter" class="com.alibaba.druid.filter.logging.Log4jFilter"> 139 <property name="statementExecutableSqlLogEnable" value="true" /> 140 </bean> 141 142 143 </beans>
3.接下写AbstractRoutingDataSource继承类
package com.goku.druid.demo.util; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * Created by nbfujx on 2017/10/18. */ public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceHolder.getDataSource(); } }
4.接下来写切面实现类
package com.goku.druid.demo.util; import java.lang.reflect.Method; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.reflect.MethodSignature; /** * Created by nbfujx on 2017/10/18. */ public class DataSourceAspect { /** * 在dao层方法之前获取datasource对象之前在切面中获取数据源 */ public void before(JoinPoint point) { Object target = point.getTarget(); System.out.println(target.toString()); String method = point.getSignature().getName(); System.out.println(method); Class<?>[] classz = target.getClass().getInterfaces(); Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()) .getMethod().getParameterTypes(); try { Method m = classz[0].getMethod(method, parameterTypes); System.out.println("method"+ m.getName()); if (m != null && m.isAnnotationPresent(DataSource.class)) { DataSource data = m.getAnnotation(DataSource.class); System.out.println("dataSource:"+data.value()); DataSourceHolder.putDataSource(data.value()); } } catch (Exception e) { e.printStackTrace(); } } }
5.还有拿到数据元的类
package com.goku.druid.demo.util; /** * Created by nbfujx on 2017/10/18. */ public class DataSourceHolder { public static final ThreadLocal<String> holder = new ThreadLocal<String>(); /** * 设置数据源 */ public static void putDataSource(String datasource) { holder.set(datasource); } /** * 获取数据源 */ public static String getDataSource() { return holder.get(); } /** * 清除数据源 */ public static void clearDataSource() { holder.remove(); } }
6.DataSource数据源注解类
package com.goku.druid.demo.util; import java.lang.annotation.ElementType; import java.lang.annotation.Target; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Created by nbfujx on 2017/10/18. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface DataSource { String value(); }
7.在service层进行数据源注解切换
package com.goku.druid.demo.service; import com.goku.druid.demo.model.FormElement; import com.goku.druid.demo.model.UserWithBLOBs; import com.goku.druid.demo.util.DataSource; /** * Created by nbfujx on 2017-10-18. */ public interface UserService { @DataSource("master") UserWithBLOBs selectByPrimaryKey(String id); @DataSource("slave") FormElement selectByPrimaryKey2(Integer id); }
GITHUB
github : https://github.com/nbfujx/learn-java-demo/tree/master/Goku.Dynamic.DruidDemo