在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() + "]");
}
}
}
感謝下面的文章,一個是教程,一個是優化時候,從切點上獲取到靈光點