基于springboot通过注解AOP动态切换druid多数据源--mybatis

基于springboot通过注解AOP动态切换druid多数据源--mybatis

 

控制于接口之上:

开始:demo地址  在lsr-core-base中

自定义注解:

/**
 * @Description: 数据源切换注解
 * @Package: lsr-microservice
 * @author: Hacker_lsr@126.com
 **/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DS {
    DataSourceType value() default DataSourceType.db1;
}

数据源标识:

/**
 * @Description: 数据源标识
 * @Package: lsr-microservice
 * @author: Hacker_lsr@126.com
 **/
public enum  DataSourceType {
    db1,db2
}

数据源配置setting:

/**
 * @Description: 数据源配置
 * @Package: lsr-microservice
 * @author: Hacker_lsr@126.com
 **/
@Configuration
@ConfigurationProperties(prefix = "spring.datasource")
public class DruidSettings {
    private String driverClassName;
    private String url;
    private String username;
    private String password;
    private String driverClassName2;
    private String url2;
    private String username2;
    private String password2;
    private int initialSize;
    private int minIdle;
    private int maxActive;
    private long maxWait;
    private long timeBetweenEvictionRunsMillis;
    private long minEvictableIdleTimeMillis;
    private String validationQuery;
    private boolean testWhileIdle;
    private boolean testOnBorrow;
    private boolean testOnReturn;
    private boolean poolPreparedStatements;
    private String filters;
    private int maxPoolPreparedStatementPerConnectionSize;
    private boolean useGlobalDataSourceStat;
    private String connectionProperties;
//get set 
}

Druid配置类:

package cn.lsr.core.config.druid;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * = = Druid配置类
 *
 * @Version: 1.0
 * @Author: Hacker_lsr@126.com
 */
@Configuration
public class DruidConfig {
    @Autowired
    DruidSettings druidSettings;
    /**
     * 数据源db1
     * @return
     */
    //@ConfigurationProperties(prefix = "spring.datasource.db1")
    @Bean(name = "dataSource01")
    public DataSource dataSource01(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(druidSettings.getDriverClassName());
        druidDataSource.setUrl(druidSettings.getUrl());
        druidDataSource.setUsername(druidSettings.getUsername());
        druidDataSource.setPassword(druidSettings.getPassword());
        druidDataSource.setInitialSize(druidSettings.getInitialSize());
        druidDataSource.setMinIdle(druidSettings.getMinIdle());
        druidDataSource.setMaxActive(druidSettings.getMaxActive());
        druidDataSource.setMaxWait(druidSettings.getMaxWait());
        druidDataSource.setTimeBetweenEvictionRunsMillis(druidSettings.getTimeBetweenEvictionRunsMillis());
        druidDataSource.setMinEvictableIdleTimeMillis(druidSettings.getMinEvictableIdleTimeMillis());
        druidDataSource.setValidationQuery(druidSettings.getValidationQuery());
        druidDataSource.setTestWhileIdle(druidSettings.isTestWhileIdle());
        druidDataSource.setTestOnBorrow(druidSettings.isTestOnBorrow());
        druidDataSource.setTestOnReturn(druidSettings.isTestOnReturn());
        druidDataSource.setPoolPreparedStatements(druidSettings.isPoolPreparedStatements());
        try {
            druidDataSource.setFilters(druidSettings.getFilters());
        } catch (Exception e) {
            e.printStackTrace();
        }
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(druidSettings.getMaxPoolPreparedStatementPerConnectionSize());
        druidDataSource.setUseGlobalDataSourceStat(druidSettings.isUseGlobalDataSourceStat());
        druidDataSource.setConnectionProperties(druidSettings.getConnectionProperties());
        return druidDataSource;
    }

    /**
     * 数据源db2
     * @return
     */
    //@ConfigurationProperties(prefix = "spring.datasource.db2")
    @Bean(name = "dataSource02")
    public DataSource dataSource02(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(druidSettings.getDriverClassName2());
        druidDataSource.setUrl(druidSettings.getUrl2());
        druidDataSource.setUsername(druidSettings.getUsername2());
        druidDataSource.setPassword(druidSettings.getPassword2());
        druidDataSource.setInitialSize(druidSettings.getInitialSize());
        druidDataSource.setMinIdle(druidSettings.getMinIdle());
        druidDataSource.setMaxActive(druidSettings.getMaxActive());
        druidDataSource.setMaxWait(druidSettings.getMaxWait());
        druidDataSource.setTimeBetweenEvictionRunsMillis(druidSettings.getTimeBetweenEvictionRunsMillis());
        druidDataSource.setMinEvictableIdleTimeMillis(druidSettings.getMinEvictableIdleTimeMillis());
        druidDataSource.setValidationQuery(druidSettings.getValidationQuery());
        druidDataSource.setTestWhileIdle(druidSettings.isTestWhileIdle());
        druidDataSource.setTestOnBorrow(druidSettings.isTestOnBorrow());
        druidDataSource.setTestOnReturn(druidSettings.isTestOnReturn());
        druidDataSource.setPoolPreparedStatements(druidSettings.isPoolPreparedStatements());
        try {
            druidDataSource.setFilters(druidSettings.getFilters());
        } catch (Exception e) {
            e.printStackTrace();
        }
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(druidSettings.getMaxPoolPreparedStatementPerConnectionSize());
        druidDataSource.setUseGlobalDataSourceStat(druidSettings.isUseGlobalDataSourceStat());
        druidDataSource.setConnectionProperties(druidSettings.getConnectionProperties());

        return druidDataSource;
    }

    /**
     * 动态数据源管理
     * @return
     */
    @Primary
    @Bean(name = "dynamicDataSource")
    public DataSource dynamicDataSource(){
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        //设置默认数据源
        dynamicDataSource.setDefaultTargetDataSource(dataSource01());
        Map<Object,Object> dbMap = new HashMap<>();
        dbMap.put(DataSourceType.db1,dataSource01());
        dbMap.put(DataSourceType.db2,dataSource02());
        // targetDataSources 这里保存我们数据源配置的多个数据源)的数据源保存到resolvedDataSources
        dynamicDataSource.setTargetDataSources(dbMap);
        return dynamicDataSource;
    }

    /**
     * 将动态数据源放入事务管理器
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager(){
        return new  DataSourceTransactionManager(dynamicDataSource());
    }
    /**
     *  配置监控服务器
     **/
    @Bean
    public ServletRegistrationBean statViewServlet(){
        ServletRegistrationBean bean = new ServletRegistrationBean(
                new StatViewServlet(), "/druid/*");
        Map<String,String> initParams = new HashMap<>();
        // druid后台管理员用户
        initParams.put("loginUsername","admin");
        initParams.put("loginPassword","123456");
        // 是否能够重置数据
        initParams.put("resetEnable", "false");

        bean.setInitParameters(initParams);
        return bean;
    }

    /**
     *  配置web监控的过滤器
     **/
    @Bean
    public FilterRegistrationBean webStatFilter(){
        FilterRegistrationBean bean = new FilterRegistrationBean(
                new WebStatFilter());
        // 添加过滤规则
        bean.addUrlPatterns("/*");
        Map<String,String> initParams = new HashMap<>();
        // 忽略过滤格式
        initParams.put("exclusions","*.js,*.css,*.icon,*.png,*.jpg,/druid/*");
        bean.setInitParameters(initParams);
        return  bean;
    }

}

动态数据源切换:

/**
 * @Description: 动态数据源切换
 * @Package: lsr-microservice
 * @author: Hacker_lsr@126.com
 **/
public class DynamicDataSource extends AbstractRoutingDataSource {
    private static final Logger log = LoggerFactory.getLogger(DynamicDataSource.class);
    // 当前线程数据源
    private static final ThreadLocal<DataSourceType> dataSourceContext = new ThreadLocal<>();
    @Override
    protected Object determineCurrentLookupKey() {
        log.info("数据源:{}",getDataSource());
        return getDataSource();
    }

    /**
     * 获取当前数据源
     * @return
     */
    public DataSourceType getDataSource(){
        return dataSourceContext.get();
    }

    /**
     * 设置数据源
     * @param dataSourceType
     */
    public static void setDataSource(DataSourceType dataSourceType){
        dataSourceContext.set(dataSourceType);
    }

    /**
     * 删除数据源
     */
    public static void clearDataSource(){
        dataSourceContext.remove();
    }
}

注解动态数据源切换实现:

/**
 * @Description: 动态数据源AOP
 * @Package: lsr-microservice
 * @author: Hacker_lsr@126.com
 **/
@Aspect
@Order(1)
@Component
public class DynamicDataSourceAspect {
    @Before("@annotation(ds)")
    public void beforeSwitchDS(JoinPoint joinPoint,DS ds){
        //获取当前访问的class
        Class<?> className = joinPoint.getTarget().getClass();
        //获取方法名
        String methodName = joinPoint.getSignature().getName();
        //获取方法的参数类型
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature)signature;
        Class[] arrClass = methodSignature.getParameterTypes();
        //默认数据源
        DataSourceType dataSourceType = DataSourceType.db1;
        try {
            //得到方法对象
            Method method = className.getMethod(methodName, arrClass);
            //判断是否有注解存在
            if (method.isAnnotationPresent(DS.class)){
                //拿到注解方法
                DS dsValue = method.getAnnotation(DS.class);
                //拿到注解value
                dataSourceType = dsValue.value();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        //切换数据源
        DynamicDataSource.setDataSource(dataSourceType);
    }
    @After("@annotation(ds)")
    public void afterSwitchDS(JoinPoint joinPoint,DS ds){
        DynamicDataSource.clearDataSource();
    }
}

application.properties##################################### 配置数据源 #####################################

##################################### 配置数据源 #####################################
datasource.db1url=192.168.0.104:3306/lsr-microservice
datasource.db2url=192.168.0.104:3306/lsr-microservice
##################################### 数据源1 #######################################
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://${datasource.db1url}?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=lishirui
##################################### 数据源2 #######################################
spring.datasource.driver-class-name2=com.mysql.jdbc.Driver
spring.datasource.url2=jdbc:mysql://${datasource.db1url}?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
spring.datasource.username2=root
spring.datasource.password2=lishirui
##################################### druid连接池 ###################################
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=60000
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
#配置监控统计拦截的filters.去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource.filters=stat,wall,slf4j
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.useGlobalDataSourceStat=true
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

使用:@DS(DataSourceType.db1)

public interface UserMapper extends MyMapper<User> {

    User selectByName(String username);

    User selectUserByName(String username);
    @DS(DataSourceType.db1)
    User selecTest(String username);

}

 

上一篇:SpringBoot-配置文件属性注入-2


下一篇:Spring Boot 学习(一) 整合Druid数据源