重写determineCurrentLookupKey()方法,返回数据源对应的KEY,这里是直接从ThreadLocal中取值,就是上文封装的DataSourceHolder。
定义一个注解为了操作方便且低耦合,不能每次需要切换的数据源的时候都要手动调一下接口吧,可以定义一个切换数据源的注解,如下:
/** * 切换数据源的注解 */ @Target(value = ElementType.METHOD) @Retention(value = RetentionPolicy.RUNTIME) @Documented public @interface SwitchSource { /** * 默认切换的数据源KEY */ String DEFAULT_NAME = "hisDataSource"; /** * 需要切换到数据的KEY */ String value() default DEFAULT_NAME; }注解中只有一个value属性,指定了需要切换数据源的KEY。
有注解还不行,当然还要有切面,代码如下:
@Aspect //优先级设置到最高 @Order(Ordered.HIGHEST_PRECEDENCE) @Component @Slf4j public class DataSourceAspect { @Pointcut("@annotation(SwitchSource)") public void pointcut() { } /** * 在方法执行之前切换到指定的数据源 * @param joinPoint */ @Before(value = "pointcut()") public void beforeOpt(JoinPoint joinPoint) { /*因为是对注解进行切面,所以这边无需做过多判定,直接获取注解的值,进行环绕,将数据源设置成远方,然后结束后,清楚当前线程数据源*/ Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); SwitchSource switchSource = method.getAnnotation(SwitchSource.class); log.info("[Switch DataSource]:" + switchSource.value()); DataSourceHolder.setDataSource(switchSource.value()); } /** * 方法执行之后清除掉ThreadLocal中存储的KEY,这样动态数据源会使用默认的数据源 */ @After(value = "pointcut()") public void afterOpt() { DataSourceHolder.clearDataSource(); log.info("[Switch Default DataSource]"); } }这个ASPECT很容易理解,beforeOpt()在方法之前执行,取值@SwitchSource中value属性设置到ThreadLocal中;afterOpt()方法在方法执行之后执行,清除掉ThreadLocal中的KEY,保证了如果不切换数据源,则用默认的数据源。
如何与Mybatis整合?单一数据源与Mybatis整合上文已经详细讲解了,数据源DataSource作为参数构建了SqlSessionFactory,同样的思想,只需要把这个数据源换成动态数据源即可。注入的代码如下:
/** * 创建动态数据源的SqlSessionFactory,传入的是动态数据源 * @Primary这个注解很重要,如果项目中存在多个SqlSessionFactory,这个注解一定要加上 */ @Primary @Bean("sqlSessionFactory2") public SqlSessionFactory sqlSessionFactoryBean(DynamicDataSource dynamicDataSource) throws Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dynamicDataSource); org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); configuration.setMapUnderscoreToCamelCase(true); configuration.setDefaultFetchSize(100); configuration.setDefaultStatementTimeout(30); sqlSessionFactoryBean.setConfiguration(configuration); return sqlSessionFactoryBean.getObject(); }