zoukankan      html  css  js  c++  java
  • 通过apo切面,动态切换数据源

    一.定义数据源注解

    1.1 数据源注解

    package com.spplus.dbservice.dynamicds;
    
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import java.lang.annotation.ElementType;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    public @interface DS {
        String value() default "titan-master";
    }

    1.2 数据源容器

    package com.spplus.dbservice.dynamicds;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class DataSourceContextHolder {
        public static final Logger log = LoggerFactory.getLogger(DataSourceContextHolder.class);
    
        /**
         * 默认数据源
         */
        public static final String DEFAULT_DS = "ssb_test2";
    
        private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
    
        // 设置数据源名
        public static void setDB(String dbType) {
            log.debug("切换到{}数据源", dbType);
            contextHolder.set(dbType);
        }
    
        // 获取数据源名
        public static String getDB() {
            return (contextHolder.get());
        }
    
        // 清除数据源名
        public static void clearDB() {
            contextHolder.remove();
        }
    }

    1.3 动态数据源

    继承AbstractRoutingDataSource ,重新实现接口determineCurrentLookupKey。该类会在spring获取数据源之前,自动调用。 

    package com.spplus.dbservice.dynamicds;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    public class DynamicDataSource extends AbstractRoutingDataSource {
        private static final Logger log = LoggerFactory.getLogger(DynamicDataSource.class);
    
        @Override
        protected Object determineCurrentLookupKey() {
            log.debug("数据源为{}", DataSourceContextHolder.getDB());
    
            return DataSourceContextHolder.getDB();
        }
    
    }

    二:定义切面

    package com.spplus.dbservice.dynamicds;
    
    import java.lang.reflect.Method;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    
    
    @Aspect
    @Component
    @Order(-1)        // 注意:这个地方为-1,确保被最先调用到
    public class DynamicDataSourceAspect {
    
        @Before("@annotation(DS)")
        public void beforeSwitchDS(JoinPoint point){
    
            //获得当前访问的class
            Class<?> className = point.getTarget().getClass();
    
            //获得访问的方法名
            String methodName = point.getSignature().getName();
            //得到方法的参数的类型
           // Class[] argClass = point.getSignature().getParameterTypes();
            
            Class[] argClass = ((MethodSignature)point.getSignature()).getMethod().getParameterTypes();
            
            String dataSource = DataSourceContextHolder.DEFAULT_DS;
            try {
                // 得到访问的方法对象
                Method method = className.getMethod(methodName,argClass);
    
                // 判断是否存在@DS注解
                if (method.isAnnotationPresent(DS.class)) {
                    DS annotation = method.getAnnotation(DS.class);
                    // 取出注解中的数据源名
                    dataSource = annotation.value();
                }
            } catch (Exception e) {
                e.printStackTrace();
               }
    
            // 切换数据源
            DataSourceContextHolder.setDB(dataSource);
    
        }
    
    
        @After("@annotation(DS)")
        public void afterSwitchDS(JoinPoint point){
    
            DataSourceContextHolder.clearDB();
    
        }
    }

    三:使用

    在service层,操作数据库之前,在方法名称上面通过@DS("数据库名称")进行注解。

     

  • 相关阅读:
    next()nextLine()以及nextInt()的区别及用法【转载】
    JAVA集合 list set map
    JAVA求回文数
    左移右移操作_进制转换与区分
    window_mysql踩坑
    centos_mysql踩坑
    【纪中受难记】——C3D6:大小不分
    zzLinux 中直接 I/O 机制的介绍https://www.ibm.com/developerworks/cn/linux/l-cn-directio/
    zz-zookeeper 启动失败 BindException: Address already in use 或者Error contacting service. It is probably not running
    zz---对象存储(Object-based Storage)概述
  • 原文地址:https://www.cnblogs.com/spplus/p/7493768.html
Copyright © 2011-2022 走看看