IT必备技能框架建设收集

springboot动态切换数据源两种方法示例

2020-09-26  本文已影响0人  haiyong6

动态切换数据源,无非是继承org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource这个类,重写determineCurrentLookupKey()这个方法,动态变换数据源的key值,下面介绍两个方法。

方法一

最简单的方法,已经有人把详细代码封装到框架中只要maven引入配置一下,就可以了:dynamic-datasource-spring-boot-starter

maven引入:

<!-- https://mvnrepository.com/artifact/com.baomidou/dynamic-datasource-spring-boot-starter -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.2.1</version>
</dependency>

application.properties文件里把原先的数据源配置注释掉,写入新的配置:

#spring.datasource.url=jdbc\:oracle\:thin\:@127.0.0.1\:1521\:xe
#spring.datasource.username=zhaohy
#spring.datasource.password=oracle
#spring.datasource.driver-class-name=oracle.jdbc.OracleDriver

#set default datasource
spring.datasource.dynamic.primary=master
spring.datasource.dynamic.datasource.master.url=jdbc\:oracle\:thin\:@127.0.0.1\:1521\:xe
spring.datasource.dynamic.datasource.master.username=name1
spring.datasource.dynamic.datasource.master.password=xxx
spring.datasource.dynamic.datasource.master.driver-class-name=oracle.jdbc.OracleDriver

spring.datasource.dynamic.datasource.slave_1.url=jdbc\:oracle\:thin\:@127.0.0.1\:1521\:xe
spring.datasource.dynamic.datasource.slave_1.username=name2
spring.datasource.dynamic.datasource.slave_1.password=xxx
spring.datasource.dynamic.datasource.slave_1.driver-class-name=oracle.jdbc.OracleDriver

参考的是官网的例子

spring:
  datasource:
    dynamic:
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
      datasource:
        master:
          url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
        slave_1:
          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
        slave_2:
          url: ENC(xxxxx) # 内置加密,使用请查看详细文档
          username: ENC(xxxxx)
          password: ENC(xxxxx)
          driver-class-name: com.mysql.jdbc.Driver
          schema: db/schema.sql # 配置则生效,自动初始化表结构
          data: db/data.sql # 配置则生效,自动初始化数据
          continue-on-error: true # 默认true,初始化失败是否继续
          separator: ";" # sql默认分号分隔符
          
       #......省略
       #以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2

这样就配置好了,master是默认数据源,slave_1是第二个数据源,名字可以随便取
如果不指定数据源,则直接是master默认的,如虚指定数据源,则可去mybatis的mapper层加注解@DS("slave_1")即可,当然也可以加在service层的方法或者类上面。如果只是指定@DS则负载均衡的访问配置好的数据库,如果不是主从数据库还是不要用这个。

测试:
controller:

@RequestMapping("/test/test1.do")
    public void test1(HttpServletRequest request) {
        testService.test1();
    }

serviceImpl:

public void test1() {
        List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
        Map<String, Object> paramsMap = new HashMap<String, Object>();
        list = testMapper.getUserList(paramsMap);
        System.out.println("===" + JSON.toJSONString(list));
        list = testMapper.getUserList1(paramsMap);
        System.out.println("1===" + JSON.toJSONString(list));
    }

mapper:

package com.zhaohy.app.dao;

import java.util.List;
import java.util.Map;

import com.baomidou.dynamic.datasource.annotation.DS;

public interface TestMapper {

    List<Map<String, Object>> getUserList(Map<String, Object> paramsMap);

    @DS("slave_1")
    List<Map<String, Object>> getUserList1(Map<String, Object> paramsMap);

}

xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhaohy.app.dao.TestMapper">
    
    <select id="getUserList" resultType="java.util.HashMap">
    select * from da_user
    </select>
    
    <select id="getUserList1" resultType="java.util.HashMap">
    select * from da_user
    </select>
</mapper>

运行效果:


动态数据源测试效果图

从上图可以看到,因为两个数据库的da_user的条数不同,第一个查到了4条,第二个查到了9条,可见生效了。

springboot默认的数据源连接池是HikariDataSource,这个开源动态数据源框架也支持阿里的druid.

集成druid

maven引入druid

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.24</version>
        </dependency>

更改数据源配置:

#spring.datasource.url=jdbc\:oracle\:thin\:@127.0.0.1\:1521\:xe
#spring.datasource.username=zhaohy
#spring.datasource.password=oracle
#spring.datasource.driver-class-name=oracle.jdbc.OracleDriver

#set druid
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=123456

#set default datasource
spring.datasource.dynamic.primary=master
spring.datasource.dynamic.datasource.master.url=jdbc\:oracle\:thin\:@127.0.0.1\:1521\:xe
spring.datasource.dynamic.datasource.master.username=zhaohy
spring.datasource.dynamic.datasource.master.password=oracle
spring.datasource.dynamic.datasource.master.driver-class-name=oracle.jdbc.OracleDriver

spring.datasource.dynamic.datasource.slave_1.url=jdbc\:oracle\:thin\:@39.100.143.84\:1521\:xe
spring.datasource.dynamic.datasource.slave_1.username=zhaohy
spring.datasource.dynamic.datasource.slave_1.password=oracle
spring.datasource.dynamic.datasource.slave_1.driver-class-name=oracle.jdbc.OracleDriver

spring.datasource.dynamic.datasource.master.druid.initial-size=3
spring.datasource.dynamic.datasource.master.druid.max-active=8
spring.datasource.dynamic.datasource.master.druid.min-idle=2
spring.datasource.dynamic.datasource.master.druid.max-wait=-1
spring.datasource.dynamic.datasource.master.druid.min-evictable-idle-time-millis=30000
spring.datasource.dynamic.datasource.master.druid.max-evictable-idle-time-millis=30000
spring.datasource.dynamic.datasource.master.druid.time-between-eviction-runs-millis=0
spring.datasource.dynamic.datasource.master.druid.validation-query=select 1 from dual
spring.datasource.dynamic.datasource.master.druid.validation-query-timeout=-1
spring.datasource.dynamic.datasource.master.druid.test-on-borrow=false
spring.datasource.dynamic.datasource.master.druid.test-on-return=false
spring.datasource.dynamic.datasource.master.druid.test-while-idle=true
spring.datasource.dynamic.datasource.master.druid.pool-prepared-statements=true
spring.datasource.dynamic.datasource.master.druid.filters=stat,wall
spring.datasource.dynamic.datasource.master.druid.share-prepared-statements=true

在springboot启动类上排除原生Druid的快速配置类。

package com.zhaohy.app;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import com.zhaohy.app.sys.filter.LoginProcessFilter;
import com.zhaohy.app.utils.OnLineCountListener;

@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
@MapperScan("com.zhaohy.app.dao")
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
        System.out.println("springboot started...");
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public FilterRegistrationBean myFilterRegistration() {
        FilterRegistrationBean regist = new FilterRegistrationBean(new LoginProcessFilter());
        // 过滤全部请求
        regist.addUrlPatterns("/*");//过滤url
        regist.setOrder(1);//过滤器顺序
        return regist;
    }
    
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public ServletListenerRegistrationBean listenerRegist() {
        ServletListenerRegistrationBean srb = new ServletListenerRegistrationBean();
        srb.setListener(new OnLineCountListener());
        System.out.println("listener====");
        return srb;
    }
}

为什么要排除?

DruidDataSourceAutoConfigure在DynamciDataSourceAutoConfiguration之前,其会注入一个DataSourceWrapper,会在原生的spring.datasource下找url,username,password等。而我们动态数据源的配置路径是变化的。

这样,再次运行,也可以得到同样的结果。

方法二

可以根据实现原理,自己实现一下。
pom.xml注释掉动态框架依赖

<!-- 动态数据源jar -->
        <!-- <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.2.1</version>
        </dependency> -->
        
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.24</version>
        </dependency>

注释掉applicaton.properties文件里的相关数据源配置

#set druid
#spring.datasource.druid.stat-view-servlet.login-username=admin
#spring.datasource.druid.stat-view-servlet.login-password=123456

#set default datasource
#spring.datasource.dynamic.primary=master
#spring.datasource.dynamic.datasource.master.url=jdbc\:oracle\:thin\:@127.0.0.1\:1521\:xe
#spring.datasource.dynamic.datasource.master.username=name1
#spring.datasource.dynamic.datasource.master.password=xxx
#spring.datasource.dynamic.datasource.master.driver-class-name=oracle.jdbc.OracleDriver
#
#spring.datasource.dynamic.datasource.slave_1.url=jdbc\:oracle\:thin\:@127.0.0.1\:1521\:xe
#spring.datasource.dynamic.datasource.slave_1.username=name2
#spring.datasource.dynamic.datasource.slave_1.password=xxx
#spring.datasource.dynamic.datasource.slave_1.driver-class-name=oracle.jdbc.OracleDriver
#
#spring.datasource.dynamic.datasource.master.druid.initial-size=3
#spring.datasource.dynamic.datasource.master.druid.max-active=8
#spring.datasource.dynamic.datasource.master.druid.min-idle=2
#spring.datasource.dynamic.datasource.master.druid.max-wait=-1
#spring.datasource.dynamic.datasource.master.druid.min-evictable-idle-time-millis=30000
#spring.datasource.dynamic.datasource.master.druid.max-evictable-idle-time-millis=30000
#spring.datasource.dynamic.datasource.master.druid.time-between-eviction-runs-millis=0
#spring.datasource.dynamic.datasource.master.druid.validation-query=select 1 from dual
#spring.datasource.dynamic.datasource.master.druid.validation-query-timeout=-1
#spring.datasource.dynamic.datasource.master.druid.test-on-borrow=false
#spring.datasource.dynamic.datasource.master.druid.test-on-return=false
#spring.datasource.dynamic.datasource.master.druid.test-while-idle=true
#spring.datasource.dynamic.datasource.master.druid.pool-prepared-statements=true
#spring.datasource.dynamic.datasource.master.druid.filters=stat,wall
#spring.datasource.dynamic.datasource.master.druid.share-prepared-statements=true

在src/main/resources下面新建applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
       default-lazy-init="true">

    <!-- Service XML资源导入-->
      <import resource="classpath:database.xml"/>
</beans>

新建database.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
       default-lazy-init="true">

    <!-- 父数据源 -->
    <bean id="baseDataSource" abstract="true"
          class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
          destroy-method="close">
        <!-- 配置初始化大小、最小、最大 -->
        <property name="initialSize" value="3"/>
        <property name="minIdle" value="2"/>
        <property name="maxActive" value="8"/>

        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="-1"/>
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="0"/>

        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="30000"/>

        <property name="validationQuery" value="select 1 from dual"/>
        <property name="testWhileIdle" value="true"/>
        <property name="testOnBorrow" value="false"/>
        <property name="testOnReturn" value="false"/>

        <!-- 打开PSCache,并且指定每个连接上PSCache的大小 如果用Oracle,则把poolPreparedStatements配置为true,mysql可以配置为false。 -->
        <property name="poolPreparedStatements" value="true"/>
        <property name="maxOpenPreparedStatements" value="20" />
        <!-- <property name="maxPoolPreparedStatementPerConnectionSize"
                  value="${druid.maxPoolPreparedStatementPerConnectionSize}"/> -->

        <!-- 配置监控统计拦截的filters -->
        <property name="filters" value="stat,wall"/>
        <!--property name="proxyFilters"> <list> <ref bean="log-filter" /> </list>
            </property -->
    </bean>

    <bean id="log-filter" class="com.alibaba.druid.filter.logging.Slf4jLogFilter">
        <property name="statementExecutableSqlLogEnable" value="true"/>
    </bean>

    <!--写数据 -->
    <bean id="writeDataSource" parent="baseDataSource">
        <property name="name" value="xe"/>
        <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:xe"/>
        <property name="username" value="name1"/>
        <property name="password" value="xxx"/>
        <property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
    </bean>

<!-- druid数据源2-->
    <bean id="dataSourceDruid2" parent="baseDataSource">
        <property name="name" value="xe"/>
        <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:xe"/>
        <property name="username" value="name1"/>
        <property name="password" value="xxx"/>
        <property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
    </bean>

    <!-- 支持oracle数据库的clob字段处理 -->
    <bean id="lobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler"
          lazy-init="true"/>

    <!-- 动态数据源 -->
    <bean id="dataSource" class="com.zhaohy.app.utils.DynamicDataSource" primary="true">
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <entry value-ref="writeDataSource" key="master"></entry>
                <entry value-ref="dataSourceDruid2" key="slave_1"></entry>
            </map>
        </property>
        <property name="defaultTargetDataSource" ref="writeDataSource"></property>
    </bean>
</beans>

新建DynamicDataSource继承AbstractRoutingDataSource重写determineCurrentLookupKey()方法

/*    */ package com.zhaohy.app.utils;
/*    */ 
/*    */ import java.util.Map;
/*    */ import javax.sql.DataSource;
/*    */ import org.slf4j.Logger;
/*    */ import org.slf4j.LoggerFactory;
/*    */ import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/*    */ import org.springframework.jdbc.datasource.lookup.DataSourceLookup;
/*    */ 
/*    */ public class DynamicDataSource
/*    */   extends AbstractRoutingDataSource
/*    */ {
/* 17 */   private static final Logger log = LoggerFactory.getLogger(DynamicDataSource.class);
/*    */ 
/*    */ 
/*    */   
/*    */   public static final String DATASOURCE_BEAN_CLASS = "com.alibaba.druid.pool.DruidDataSource";
/*    */ 
/*    */   
/*    */   private int readDBSize;
/*    */ 
/*    */ 
/*    */   
/*    */   protected Object determineCurrentLookupKey() {
/* 29 */      String dsKey = DynamicDataSourceContextHolder.getDataSourceRouterKey();
/* 31 */      dsKey = (dsKey == null) ? "master" : dsKey;
/* 34 */     log.info("当前数据源key:{}", dsKey);
/* 35 */     return dsKey;
/*    */   }
/*    */ 
/*    */ 
/*    */ 
/*    */ 
/*    */ 
/*    */   
/* 43 */   public void setDataSourceLookup(DataSourceLookup dataSourceLookup) { super.setDataSourceLookup(dataSourceLookup); }
/*    */ 
/*    */ 
/*    */ 
/*    */ 
/*    */ 
/*    */ 
/*    */   
/* 51 */   public void setDefaultTargetDataSource(Object defaultTargetDataSource) { super.setDefaultTargetDataSource(defaultTargetDataSource); }
/*    */ 
/*    */ 
/*    */ 
/*    */ 
/*    */ 
/*    */ 
/*    */   
/* 59 */   public void setTargetDataSources(Map<Object, Object> targetDataSources) { super.setTargetDataSources(targetDataSources); }
/*    */ 
/*    */ 
/*    */ 
/*    */ 
/*    */ 
/*    */   
/* 66 */   public DataSource getTargetDataSource() { return determineTargetDataSource(); }
/*    */ 
/*    */ 
/*    */ 
/*    */   
/* 71 */   public void setReadDBSize(int readDBSize) { this.readDBSize = readDBSize; }
/*    */ 
/*    */ 
/*    */   
/* 75 */   public int getReadDBSize() { return this.readDBSize; }
}

新建DynamicDataSourceContextHolder类:

package com.zhaohy.app.utils;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DynamicDataSourceContextHolder {
    private static Logger logger = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);

    /**
     * 存储已经注册的数据源的key
     */
    public static List<String> dataSourceIds = new ArrayList<>();

    /**
     * 线程级别的私有变量
     */
    private static final ThreadLocal<String> HOLDER = new ThreadLocal<>();

    public static String getDataSourceRouterKey () {
        return HOLDER.get();
    }

    public static void setDataSourceRouterKey (String dataSourceRouterKey) {
        logger.info("切换至{}数据源", dataSourceRouterKey);
        HOLDER.set(dataSourceRouterKey);
    }

    /**
     * 设置数据源之前一定要先移除
     */
    public static void removeDataSourceRouterKey () {
        HOLDER.remove();
    }

    /**
     * 判断指定DataSrouce当前是否存在
     *
     * @param dataSourceId
     * @return
     */
    public static boolean containsDataSource(String dataSourceId){
        return dataSourceIds.contains(dataSourceId);
    }
}

上面这个类中用到ThreadLocal ,保证线程安全。

新建Datasource注解类

package com.zhaohy.app.sys.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Datasource {
    String name();
}

@Target注解里面参数解释:
METHOD 可用于方法上
TYPE 可用于类或者接口上
ANNOTATION_TYPE 可用于注解类型上(被@interface修饰的类型)
CONSTRUCTOR 可用于构造方法上
FIELD 可用于域上
LOCAL_VARIABLE 可用于局部变量上
PACKAGE 用于记录java文件的package信息
PARAMETER 可用于参数上

新建DynamicDataSourceAspect切面类:

package com.zhaohy.app.sys.aspect;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import com.zhaohy.app.sys.annotation.Datasource;
import com.zhaohy.app.utils.DynamicDataSourceContextHolder;

/**
 * 定义日志切面
 * 
 * @author zhaohy
 * @Lazy 注解:容器一般都会在启动的时候实例化所有单实例 bean,如果我们想要 Spring 在启动的时候延迟加载 bean,需要用到这个注解
 *       value为true、false 默认为true,即延迟加载,@Lazy(false)表示对象会在初始化的时候创建
 */
@Aspect
@Component
@Lazy(false)
public class DynamicDataSourceAspect {
    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);


    @Before("@annotation(ds)")
    public void begin(JoinPoint joinPoint, Datasource ds) {
        //System.out.println("========" + ds.name());
        // 动态切换数据源
        DynamicDataSourceContextHolder.setDataSourceRouterKey(ds.name());
    }

    @After("@annotation(ds)")
    public void after(JoinPoint point, Datasource ds) {
        //System.out.println("==@After==  finally returning");
        // 数据源重置
        DynamicDataSourceContextHolder.removeDataSourceRouterKey();
    }

    /**
     * 获取方法中声明的注解
     *
     * @param joinPoint
     * @return
     * @throws NoSuchMethodException
     */
    public Datasource getDeclaredAnnotation(ProceedingJoinPoint joinPoint) throws NoSuchMethodException {
        // 获取方法名
        String methodName = joinPoint.getSignature().getName();
        // 反射获取目标类
        Class<?> targetClass = joinPoint.getTarget().getClass();
        // 拿到方法对应的参数类型
        Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
        // 根据类、方法、参数类型(重载)获取到方法的具体信息
        Method objMethod = targetClass.getMethod(methodName, parameterTypes);
        // 拿到方法定义的注解信息
        Datasource annotation = objMethod.getDeclaredAnnotation(Datasource.class);
        // 返回
        return annotation;
    }
}

修改mapper中的注解为自定义@Datasource注解

package com.zhaohy.app.dao;

import java.util.List;
import java.util.Map;

import com.zhaohy.app.sys.annotation.Datasource;

//import com.baomidou.dynamic.datasource.annotation.DS;

public interface TestMapper {

    List<Map<String, Object>> getUserList(Map<String, Object> paramsMap);

    //@DS("slave_1")
    @Datasource(name="slave_1")
    List<Map<String, Object>> getUserList1(Map<String, Object> paramsMap);

}

修改启动类引入applicationContext.xml

package com.zhaohy.app;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ImportResource;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import com.zhaohy.app.sys.filter.LoginProcessFilter;
import com.zhaohy.app.utils.OnLineCountListener;

@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
@MapperScan("com.zhaohy.app.dao")
@ImportResource({"classpath:applicationContext.xml"})
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
        System.out.println("springboot started...");
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public FilterRegistrationBean myFilterRegistration() {
        FilterRegistrationBean regist = new FilterRegistrationBean(new LoginProcessFilter());
        // 过滤全部请求
        regist.addUrlPatterns("/*");//过滤url
        regist.setOrder(1);//过滤器顺序
        return regist;
    }
    
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public ServletListenerRegistrationBean listenerRegist() {
        ServletListenerRegistrationBean srb = new ServletListenerRegistrationBean();
        srb.setListener(new OnLineCountListener());
        System.out.println("listener====");
        return srb;
    }
}

运行效果如图:


动态数据源测试效果图2

可以看到,同样可以实现动态切换数据源,主要是基于aop在每次访问数据库之前动态指定一下数据源的key,两个连接池在启动的时候就已经加载好了,只是动态的去找哪个池子拿连接而已。

总结

第二种自己实现的方法功能比较简陋,没有做负载均衡策略,追求简单的话,可以直接用第一种别人写好的,原理应该就是第二种的实现方式,具体第一种的源码没去看,原理应该是一样的。

上一篇 下一篇

猜你喜欢

热点阅读