摘要: 本篇文章的場景是做排程中心和監控中心時的需求,後端使用TDDL實現分表分庫,需求:實現關鍵業務的查詢監控,當用Mybatis查詢資料時需要從主庫切換到備庫或者直接連到備庫上查詢,從而減小主庫的壓力,在本篇文章中主要記錄在Spring Boot中通過自定義註解結合AOP實現直接連線備庫查詢。
一.通過AOP 自定義註解實現主庫到備庫的切換
1.1 自定義註解
自定義註解如下程式碼所示
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SwitchDataBase {
boolean switch2Backup() default false;
}複製程式碼
1.2 實現方法攔截器對自定義註解處理
import java.lang.reflect.Method;
import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* 處理走備庫邏輯的註解
*/
@Component
public class SwitchDataBaseInterceptor implements MethodInterceptor {
private final Logger log = LoggerFactory.getLogger(SwitchDataBaseInterceptor.class);
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
SwitchDataBase annotation = getAnnotation(method);
if (annotation == null) {
return invocation.proceed();
}
Object val = null;
if(!ThreadLocalMap.containsKey(GroupDataSourceRouteHelper.DATASOURCE_INDEX)) {
if (annotation.switch2Backup()) {
log.info("query back up DB, method: " + method.getName());
GroupDataSourceRouteHelper.executeByGroupDataSourceIndex(1, true);
} else {
log.info("query primary DB, method: " + method.getName());
GroupDataSourceRouteHelper.executeByGroupDataSourceIndex(0, true);
}
}
try {
val = invocation.proceed();
} catch (Exception e) {
log.info(method.getDeclaringClass().getName() + "." +
invocation.getMethod().getName() + "方法呼叫失敗,arguments:" +
Arrays.toString(invocation.getArguments()));
throw new RuntimeException(e);
} finally {
GroupDataSourceRouteHelper.removeGroupDataSourceIndex();
}
return val;
}
/**
* 找方法上面宣告的註解
*/
private SwitchDataBase getAnnotation(Method method) {
if (method.isAnnotationPresent(SwitchDataBase.class)) {
return method.getAnnotation(SwitchDataBase.class);
}
return null;
}
}複製程式碼
1.3 配置OverallQueryConfiguration
在Spring Boot中裝配AOP Bean,實現掃描特定目錄下的註解,實現切面變成形成通知處理。示例程式碼如下
import com.wdk.wms.annotation.SwitchDataBaseInterceptor;
import org.springframework.aop.Advisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SwitchDataBaseConfiguration {
@Bean(name = "overallQueryInterceptor")
public SwitchDataBaseInterceptor overallQueryInterceptor() {
return new SwitchDataBaseInterceptor();
}
//新增aop的pointcut
@Bean(name = "jdkRegexpMethodPointcut")
public JdkRegexpMethodPointcut jdkRegexpMethodPointcut() {
JdkRegexpMethodPointcut jdkRegexpMethodPointcut = new JdkRegexpMethodPointcut();
jdkRegexpMethodPointcut.setPatterns("com.wdk.wms.mapper.*");
return jdkRegexpMethodPointcut;
}
//設定預設的aop配置對應的是原來的<aop:advisor>
@Bean
public Advisor druidAdvisor() {
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
defaultPointcutAdvisor.setPointcut(jdkRegexpMethodPointcut());
defaultPointcutAdvisor.setAdvice(overallQueryInterceptor());
return defaultPointcutAdvisor;
}
}複製程式碼
1.4 如何使用註解從主庫到備庫的切換
@SwitchDataBase(switch2Backup = true)
List<ConsumerNoticeMsg> listByTemplateOver3(@Param("templates") List<Integer> templates);複製程式碼