Spring Boot中自定义注解+AOP实现主备库切换

摘要: 本篇文章的场景是做调度中心和监控中心时的需求,后端使用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;/** * 处理走备库逻辑的注解 */@Componentpublic 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;@Configurationpublic 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);
(0)

相关推荐