在Spring Boot + Mybatis 动态数据源基础上,很多教程(文末附链接了)都是实现方法级别的切换,按照普遍教程都是这样的
1.声明一个自定义注解,并且带参数的
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataSource { /** * 数据源key值 * @return */ String value(); }
2.然后按照设置切点
@Before("@annotation(dataSource))")
3.再到实现上就是
@RestController @RequestMapping("user") public class SysUserController { @Autowired private SysUserService sysUserService; @DataSource(value="master") @PostMapping(value="/findAll") public Object findAll() { return sysUserService.findAll(); } @DataSource(value="slave") @PostMapping(value="/findAll2") public Object findAll2() { return sysUserService.findAll(); } }
通过方法上的注解,来切换不同的数据源
但是我懒啊
需求就来了:::::
- 我不想一个一个方法写注解,大同小异参数又没有什么大变化,都是DataSource的key
- 我想只能在类上面注解,实现整个类的数据源变化
- 我还想有的方法可能不适用,我得有优先级,如果在方法上有注解话,优先使用方法上的
开搞:如何把数据源自定义注解放在类上,然后切点去扫描类,获取切点类上面的自定义参数,来实现切换数据源
主要方向就是切点设置这边啦直接贴出来
package com.wsh.demo.asp;
import com.wsh.demo.config.dynDataSource.DynamicDataSourceContextHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @Author: wsh
*/
@Aspect
@Order(-1) // 该切面应当先于 @Transactional 执行
@Component
public class DynamicDataSourceAspect {
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 切换数据源
*/
@Around("execution(@com.wsh.demo.asp.DataSource * *(..))")
public Object aroundController(ProceedingJoinPoint pjp) throws Throwable {
// 获取切入的 Method
MethodSignature joinPointObject = (MethodSignature) pjp.getSignature();
Method method = joinPointObject.getMethod();
boolean flag = method.isAnnotationPresent(DataSource.class);
if (flag) {
DataSource dataSource = method.getAnnotation(DataSource.class);
setDataSource(dataSource,method);
} else {
// 如果方法上没有注解,则搜索类上是否有注解
DataSource classDataSource = AnnotationUtils.findAnnotation(joinPointObject.getMethod().getDeclaringClass(), DataSource.class);
if (classDataSource != null) {
setDataSource(classDataSource,method);
} else {
DynamicDataSourceContextHolder.clearDataSourceKey();
logger.info("没有注解使用默认的");
}
}
Object proceed = pjp.proceed();
// 将数据源置为默认数据源
DynamicDataSourceContextHolder.clearDataSourceKey();
return proceed;
}
private void setDataSource(DataSource dataSource,Method method ) {
if (!DynamicDataSourceContextHolder.containDataSourceKey(dataSource.value())) {
logger.info("DataSource [{}] doesn't exist, use default DataSource [{}] " + dataSource.value());
} else {
// 切换数据源
DynamicDataSourceContextHolder.setDataSourceKey(dataSource.value());
logger.info("Switch DataSource to [" + DynamicDataSourceContextHolder.getDataSourceKey() +
"] in Method [" + method.getName() + "]");
}
}
}
感谢下面的文章,一个是教程,一个是优化时候,从切点上获取到灵光点