共计 3792 个字符,预计需要花费 10 分钟才能阅读完成。
MyBatis-Plus 动静数据源须要引入 jar 包
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
应用 @DS()注解,括号内的值是咱们配置的数据源名称,通常应用的时候是配置到 mapper 层的类上;如果没有该注解则应用的是默认数据库;
@DS 的优先级也是就近准则,如果类上已有 @DS 且他的某个办法也有 @DS 那么该办法应用的数据库为办法上申明的数据库;
有些时候不同库中有雷同的表(对应一个实体类),须要在运行时动静抉择数据源。咱们能够在应用 @DS 注解的时候,应用 #通配符,将咱们的数据库以参数的形式来启用;# 参数名称能够动静的应用咱们的参数变量或者 header 和 session 中的变量;
‘#’参数的实现依赖于 com.baomidou.dynamic.datasource.processorDsProcessor
接口解决,实现形式有三个
- DsHeaderProcessor: 从申请的 header 中获取 ds 数据源名称。
- DsSessionProcessor: 从 session 中获取数据源 d 名称
- DsSpelExpressionProcessor: 通过 spel 表达式获取 ds 数据源名称,
这 3 种形式采纳的是责任链形式间断获取的。顺次执行。
DsHeaderProcessor 的拦挡格局为 @DS("#header 变量名")
@DS("#header dataName")
List<Entity> List(@Param("query") String query
DsSessionProcessor 的拦挡格局为 @DS("#session 变量名")
@DS("#session dataName")
List<Entity> List(@Param("query") String query
@DS("#dataName")
List<Entity> List(@Param("query") String query, String dataName);
其实现原理为 DynamicDataSourceAutoConfiguration 配置类 Advisor
@Bean
@ConditionalOnMissingBean
public DynamicDataSourceAnnotationAdvisor dynamicDatasourceAnnotationAdvisor(DsProcessor dsProcessor) {DynamicDataSourceAnnotationInterceptor interceptor = new DynamicDataSourceAnnotationInterceptor();
interceptor.setDsProcessor(dsProcessor);
DynamicDataSourceAnnotationAdvisor advisor = new DynamicDataSourceAnnotationAdvisor(interceptor);
advisor.setOrder(properties.getOrder());
return advisor;
}
DynamicDataSourceAnnotationAdvisor 的切点为 DS 注解
private Pointcut buildPointcut() {Pointcut cpc = new AnnotationMatchingPointcut(DS.class, true);
Pointcut mpc = AnnotationMatchingPointcut.forMethodAnnotation(DS.class);
return new ComposablePointcut(cpc).union(mpc);
}
拦截器为 DynamicDataSourceAnnotationInterceptor,拦截器会解决以 #结尾的注解值,并交由
DsProcessor 来解决
private static final String DYNAMIC_PREFIX = "#";
private String determineDatasource(MethodInvocation invocation) throws Throwable {Method method = invocation.getMethod();
DS ds = method.isAnnotationPresent(DS.class)
? method.getAnnotation(DS.class)
: AnnotationUtils.findAnnotation(RESOLVER.targetClass(invocation), DS.class);
String key = ds.value();
return (!key.isEmpty() && key.startsWith(DYNAMIC_PREFIX)) ? dsProcessor
.determineDatasource(invocation, key) : key;
}
DsHeaderProcessor 解决逻辑为从 request 的 header 中取变量值:
private static final String HEADER_PREFIX = "#header";
@Override
public boolean matches(String key) {return key.startsWith(HEADER_PREFIX);
}
@Override
public String doDetermineDatasource(MethodInvocation invocation, String key) {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
// 这一行能够看出 HEADER_PREFIX 和数据源之间须要空一位,能够使任意字符
return request.getHeader(key.substring(8));
}
DsSessionProcessor 从 seesion 中去取变量的值:
private static final String SESSION_PREFIX = "#session";
@Override
public boolean matches(String key) {return key.startsWith(SESSION_PREFIX);
}
@Override
public String doDetermineDatasource(MethodInvocation invocation, String key) {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
// 这一行能够看出 SESSION_PREFIX 和数据源之间须要空一位,能够使任意字符
return request.getSession().getAttribute(key.substring(9)).toString();}
DsSpelExpressionProcessor:
/**
* 参数发现器
*/
private static final ParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
/**
* Express 语法解析器
*/
private static final ExpressionParser PARSER = new SpelExpressionParser();
@Override
public boolean matches(String key) {return true;}
@Override
public String doDetermineDatasource(MethodInvocation invocation, String key) {Method method = invocation.getMethod();
Object[] arguments = invocation.getArguments();
EvaluationContext context = new MethodBasedEvaluationContext(null, method, arguments,
NAME_DISCOVERER);
final Object value = PARSER.parseExpression(key).getValue(context);
return value == null ? null : value.toString();}
具体的实现原理能够参考 Spring 动静数据源,源码入口为:`
com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration