1.applicationContext.xml
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 主数据源 -->
<bean id="masterDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbcDriver}" />
<property name="url" value="${jdbcUrl}" />
<property name="username" value="${jdbcUsername}" />
<property name="password" value="${jdbcPassword}" />
<property name="maxActive" value="${maxActive}" /><!-- 最大数据库连接数 -->
<property name="maxIdle" value="${maxIdle}" /><!-- 最大空闲连接数量 -->
<property name="maxWait" value="${maxWait}" /><!-- 超时等待时间,毫秒 -->
<property name="testWhileIdle" value="true" /><!-- 连接是否被回收器进行检验 -->
<property name="testOnBorrow" value="true" /><!-- 是否在从池中取出连接前进行检验 -->
<property name="validationQuery" value="select 1" />
<property name="timeBetweenEvictionRunsMillis" value="3600000" /><!-- 每隔多少时间检测一次,毫秒 -->
<property name="removeAbandoned" value="true" /><!-- 是否自动回收超时连接 -->
<property name="removeAbandonedTimeout" value="3600" /><!-- 超时时间,单位秒 -->
</bean>
<!-- 从数据源 -->
<bean id="slaveDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${slave_jdbcDriver}" />
<property name="url" value="${slave_jdbcUrl}" />
<property name="username" value="${slave_jdbcUsername}" />
<property name="password" value="${slave_jdbcPassword}" />
<property name="maxActive" value="${slave_maxActive}" />
<property name="maxIdle" value="${slave_maxIdle}" />
<property name="maxWait" value="${slave_maxWait}" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="true" />
<property name="validationQuery" value="select 1" />
<property name="timeBetweenEvictionRunsMillis" value="3600000" />
<property name="removeAbandoned" value="true" />
<property name="removeAbandonedTimeout" value="3600" />
</bean>
<bean id="dynamicDataSource" class="com.wpao.shop.util.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="master" value-ref="masterDataSource" />
<entry key="slave" value-ref="slaveDataSource" />
</map>
</property>
<property name="defaultTargetDataSource" ref="masterDataSource" />
</bean>
2.DynamicDataSource
package com.wpao.shop.util;
import org.apache.log4j.Logger;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
//数据源动态切换类:
public class DynamicDataSource extends AbstractRoutingDataSource {
Logger logger = Logger.getLogger(this.getClass());
@Override
protected Object determineCurrentLookupKey() {
String dtSoce = DataSourceSwitcher.getDataSource();
logger.info("***[shopmm]nowLookupKey:"+dtSoce);
return dtSoce;
}
}
3.DataSourceSwitcher
package com.wpao.shop.util;
//数据源选择类:
public class DataSourceSwitcher {
@SuppressWarnings("rawtypes")
private static final ThreadLocal contextHolder = new ThreadLocal();
@SuppressWarnings("unchecked")
public static void setDataSource(String dataSource) {
//Assert.notNull(dataSource, "dataSource cannot be null");
contextHolder.set(dataSource);
}
public static void setMaster() {
clearDataSource();
//setDataSource("master");
}
public static void setSlave() {
setDataSource("slave");
}
public static String getDataSource() {
return (String)contextHolder.get();
}
public static void clearDataSource() {
contextHolder.remove();
}
}
4.DataSourceAdvice
package com.wpao.shop.util;
import java.lang.reflect.Method;
import org.apache.log4j.Logger;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;
//AOP切面类:
public class DataSourceAdvice implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {
Logger logger = Logger.getLogger(this.getClass());
//service方法执行之前被调用:
public void before(Method method, Object[] args, Object target) {
try {
String inMethdName = (method != null && method.getName() != null) ? method.getName().trim() : "";
//logger.info("***[shopmm]DataSource-切入点:"+target.getClass().getName()+"类中["+inMethdName+"]方法,开始..");
String methodName = inMethdName.toLowerCase();
if(methodName.startsWith("query")) {
DataSourceSwitcher.setSlave();
logger.info("***[shopmm]DataSource-切换:["+inMethdName+"]方法已切换到:slave!");
}else if(methodName.startsWith("nei")) {
//方法的内部方法,不做切换!
logger.info("***[shopmm]DataSource-切换:["+inMethdName+"]内部方法不切换!");
}else {
DataSourceSwitcher.setMaster();
logger.info("***[shopmm]DataSource-切换:["+inMethdName+"]方法已切换回:master!");
}
}catch(Exception e) {
DataSourceSwitcher.setMaster();
logger.info("***[shopmm]DataSource-切换:出现异常,已切换回:master!Err:"+e.toString());
}
}
//service方法执行完之后被调用:
public void afterReturning(Object arg0, Method method, Object[] args, Object target) {
try {
DataSourceSwitcher.clearDataSource();
//logger.info("***[shopmm]Aop-Service执行完成:["+method.getName()+"]方法执行结束,clearDataSource!");
}catch(Exception e) {
logger.info("***[shopmm]Aop-Service执行完成:出现异常("+method.getName()+")!Err:"+e.toString());
}
}
//抛出Exception之后被调用:
public void afterThrowing(Method method, Object[] args, Object target, Exception ex) {
try {
DataSourceSwitcher.clearDataSource();
logger.info("***[shopmm]Aop-AfterThrowing:"+target.getClass().getName()+"类中["+method.getName()+"]抛出异常["+ex.toString()+"],clearDataSource!");
}catch(Exception e) {
logger.info("***[shopmm]Aop-AfterThrowing:出现异常("+target.getClass().getName()+"-"+method.getName()+")!Err:"+e.toString());
}
}
}
5.applicationContext.xml
<!-- 切换数据源71209 -->
<bean id="dataSourceAdvice" class="com.wpao.shop.util.DataSourceAdvice" />
<aop:config>
<aop:advisor pointcut="execution(* com.wpao.shop.dao.*.*(..))" advice-ref="dataSourceAdvice" />
</aop:config>