共计 3257 个字符,预计需要花费 9 分钟才能阅读完成。
摘要: 本篇文章的场景是做调度中心和监控中心时的需求,后端使用 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); |
正文完
发表至: java
2019-08-02