Spring Boot中自定義註解+AOP實現主備庫切換
阿新 • • 發佈:2019-08-02
摘要: 本篇文章的場景是做排程中心和監控中心時的需求,後端使用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);