扩展AbstractRoutingDataSource
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
*
* <p>Title: DynamicDataSource</p>
* <p>Description: 动态数据源(依赖于spring)</p>
* @author zhjie
* @date
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSource();
}
}
DataSourceContextHolder 数据源操作类
/**
*
* <p>Title: DataSourceContextHolder</p>
* <p>Description: 数据源进行操作的类</p>
* @author zhjie
* @date
*/
public class DataSourceContextHolder {
/**
* 线程本地环境
*/
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
/**
* @Description: 设置数据源
* @param dataSource 数据源名称
* @return void
* @throws
*/
public static void setDataSource(String dataSource) {
contextHolder.set(dataSource);
}
/**
* @Description: 获取数据源名称
* @param
* @return String
* @throws
*/
public static String getDataSource() {
return contextHolder.get();
}
/**
* @Description: 清除数据源名称
* @param
* @return void
* @throws
*/
public static void clearDataSource() {
contextHolder.remove();
}
}
数据源自定义注解
/**
*
* <p>Title: DataSource</p>
* <p>Description: 数据源自定义注解</p>
* @author zhjie
* @date
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String name() default DataSource.PORTAL;
public static String PORTAL = "dataSourcePortal";
public static String EMP = "dataSourceEmp";
}
在service层使用数据源自定义注解
@Service
@DataSource(name = DataSource.EMP)
public class EmpServeiceImpl implements EmpService {
@Autowired
private EmpDao empDao ;
@Override
public int addEmp(Emp emp) {
return empDao.addEmp(emp);
}
@Override
public int deleteEmp(Emp emp) {
return empDao.deleteEmp(emp);
}
@Override
public int updateEmp(Emp emp) {
return empDao.updateEmp(emp);
}
@Override
public List<Emp> getEmps(Emp emp) {
return empDao.getEmps(emp);
}
@Override
public int getCount(Emp emp) {
return empDao.getCount(emp);
}
}
自定义拦截器,拦截DataSource的值,用于切换数据源
/**
* 自定义拦截器,拦截DataSource的值
* <p>Title: DataSourceExchange</p>
* <p>Description: </p>
* @author zhjie
* @date
*/
public class DataSourceExchange implements MethodBeforeAdvice,AfterReturningAdvice
{
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
DataSourceContextHolder.clearDataSource();
}
@Override
public void before(Method method, Object[] args, Object target){
Class<?> clazz = target.getClass();
try {
Class<?>[] types = method.getParameterTypes();
// 默认使用类型注解
if (clazz.isAnnotationPresent(DataSource.class)) {
DataSource source = clazz.getAnnotation(DataSource.class);
DataSourceContextHolder.setDataSource(source.name());
}
// 方法注解可以覆盖类型注解
Method m = clazz.getMethod(method.getName(), types);
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource source = m.getAnnotation(DataSource.class);
DataSourceContextHolder.setDataSource(source.name());
}
} catch (Exception e) {
System.out.println(clazz + ":" + e.getMessage());
}
}
}
数据源xml文件定义
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 加载db.properties文件中的内容 -->
<context:property-placeholder location="classpath:config/properties/mysql.properties" />
<!-- 配置数据源,-->
<bean id="dataSourcePortal" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${portal.jdbc.driver}" />
<property name="url" value="${portal.jdbc.url}" />
<property name="username" value="${portal.jdbc.uname}" />
<property name="password" value="${portal.jdbc.password}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="${portal.jdbc.initialSize}"></property>
<!-- 连接池最大数量 -->
<property name="maxActive" value="${portal.jdbc.maxActive}"></property>
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="${portal.jdbc.maxIdle}"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="${portal.jdbc.minIdle}"></property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="${portal.jdbc.maxWait}"></property>
<!--
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<property name="initialSize" value="${initialSize}"></property>
<property name="maxActive" value="${maxActive}"></property>
<property name="maxIdle" value="${maxIdle}"></property>
<property name="minIdle" value="${minIdle}"></property>
<property name="maxWait" value="${maxWait}"></property>
-->
</bean>
<!-- 配置数据源,-->
<bean id="dataSourceEmp" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${emp.jdbc.driver}" />
<property name="url" value="${emp.jdbc.url}" />
<property name="username" value="${emp.jdbc.uname}" />
<property name="password" value="${emp.jdbc.password}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="${emp.jdbc.initialSize}"></property>
<!-- 连接池最大数量 -->
<property name="maxActive" value="${emp.jdbc.maxActive}"></property>
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="${emp.jdbc.maxIdle}"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="${emp.jdbc.minIdle}"></property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="${emp.jdbc.maxWait}"></property>
</bean>
<!-- 数据源:Spring用来控制业务逻辑。数据源、事务控制、aop -->
<bean id="dataSource" class="com.zhjie.common.datasource.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="dataSourcePortal" value-ref="dataSourcePortal"></entry>
<entry key="dataSourceEmp" value-ref="dataSourceEmp"></entry>
</map>
</property>
<!-- 默认目标数据源为你主库数据源 -->
<property name="defaultTargetDataSource" ref="dataSourcePortal"/>
</bean>
<!-- 配置sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" /><!-- 实例化sqlSessionFactory时需要使用上述配置好的数据源以及SQL映射文件 -->
<property name="mapperLocations" value="classpath*:mybatis/mappers/**/*.xml" /><!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
<property name="configLocation" value="classpath:config/xml/mybatis-config.xml"/>
</bean>
<bean id="dataSourceExchange" class="com.zhjie.common.datasource.DataSourceExchange"/>
<!-- 定义SqlSessionTemplate -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>
<!-- SqlSession:用于执行持久化操作的对象,类似于jdbc中的Connection。 -->
<!-- SqlSessionFactory:创建SqlSession实例的工厂 -->
<!-- SqlSessionFactoryBuilder:build方法创建SqlSessionFactory实例。 -->
<!-- SqlSessionTemplate:MyBatis提供的持久层访问模板化的工具,线程安全,可通过构造参数或依赖注入SqlSessionFactory实例。 -->
</beans>
配置切面拦截
<aop:config>
<!--pointcut元素定义一个切入点,execution中的第一个星号 用以匹配方法的返回类型, 这里星号表明匹配所有返回类型。 com.zhjie.servie.*.*(..)表明匹配cn.zhjie.service包下的所有类的所有方法 -->
<aop:pointcut id="myPointcut"
expression="execution(* com.zhjie.portal.service.*.*(..)) or execution(* com.zhjie.emp.service.*.*(..))" />
<!--将定义好的事务处理策略应用到上述的切入点 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" order="2"/>
<aop:advisor pointcut-ref="myPointcut" advice-ref="dataSourceExchange" order="1" />
</aop:config>
搞定!!!
有问题欢迎吐槽。。。