一.定义数据源注解
1.1 数据源注解
package com.spplus.dbservice.dynamicds; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.annotation.ElementType; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface DS { String value() default "titan-master"; }
1.2 数据源容器
package com.spplus.dbservice.dynamicds; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DataSourceContextHolder { public static final Logger log = LoggerFactory.getLogger(DataSourceContextHolder.class); /** * 默认数据源 */ public static final String DEFAULT_DS = "ssb_test2"; private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); // 设置数据源名 public static void setDB(String dbType) { log.debug("切换到{}数据源", dbType); contextHolder.set(dbType); } // 获取数据源名 public static String getDB() { return (contextHolder.get()); } // 清除数据源名 public static void clearDB() { contextHolder.remove(); } }
1.3 动态数据源
继承AbstractRoutingDataSource ,重新实现接口determineCurrentLookupKey。该类会在spring获取数据源之前,自动调用。
package com.spplus.dbservice.dynamicds; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource extends AbstractRoutingDataSource { private static final Logger log = LoggerFactory.getLogger(DynamicDataSource.class); @Override protected Object determineCurrentLookupKey() { log.debug("数据源为{}", DataSourceContextHolder.getDB()); return DataSourceContextHolder.getDB(); } }
二:定义切面
package com.spplus.dbservice.dynamicds; import java.lang.reflect.Method; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Aspect @Component @Order(-1) // 注意:这个地方为-1,确保被最先调用到 public class DynamicDataSourceAspect { @Before("@annotation(DS)") public void beforeSwitchDS(JoinPoint point){ //获得当前访问的class Class<?> className = point.getTarget().getClass(); //获得访问的方法名 String methodName = point.getSignature().getName(); //得到方法的参数的类型 // Class[] argClass = point.getSignature().getParameterTypes(); Class[] argClass = ((MethodSignature)point.getSignature()).getMethod().getParameterTypes(); String dataSource = DataSourceContextHolder.DEFAULT_DS; try { // 得到访问的方法对象 Method method = className.getMethod(methodName,argClass); // 判断是否存在@DS注解 if (method.isAnnotationPresent(DS.class)) { DS annotation = method.getAnnotation(DS.class); // 取出注解中的数据源名 dataSource = annotation.value(); } } catch (Exception e) { e.printStackTrace(); } // 切换数据源 DataSourceContextHolder.setDB(dataSource); } @After("@annotation(DS)") public void afterSwitchDS(JoinPoint point){ DataSourceContextHolder.clearDB(); } }
三:使用
在service层,操作数据库之前,在方法名称上面通过@DS("数据库名称")进行注解。