springboot项目自定义注解实现的多数据源切换
Posted geekdc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot项目自定义注解实现的多数据源切换相关的知识,希望对你有一定的参考价值。
一、主要依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.4.RELEASE</version> <relativePath/> </parent> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>2.1.4.RELEASE</version> </dependency> dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency>
二、yml
# 数据源配置 spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.jdbc.Driver druid: # 主库数据源 master: url: jdbc:mysql://127.0.0.1:3306/master?characterEncoding=UTF-8 username: root password: root #树熊数据源 slave: enabled : true url: jdbc:mysql:////127.0.0.1:3306/slave?characterEncoding=UTF-8 username: root password: root # 初始连接数 initial-size: 10 # 最大连接池数量 max-active: 100 # 最小连接池数量 min-idle: 10 # 配置获取连接等待超时的时间 max-wait: 60000 # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-pool-prepared-statement-per-connection-size: 20 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 timeBetweenEvictionRunsMillis: 60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 min-evictable-idle-time-millis: 300000 validation-query: SELECT 1 FROM DUAL test-while-idle: true test-on-borrow: false test-on-return: false stat-view-servlet: enabled: true url-pattern: /druid/* filter: stat: log-slow-sql: true slow-sql-millis: 1000 merge-sql: false wall: config: multi-statement-allow: true
三、实现
3.1、@DataSource和DataSourceType
/** * 数据源 * @author DUCHONG */ public enum DataSourceType /** * 主库 */ MASTER, /** * 从库 */ SLAVE
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义多数据源切换注解 * * @author DUCHONG */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface DataSource /** * 切换数据源名称 */ public DataSourceType value() default DataSourceType.MASTER;
3.2、DynamicDataSourceContextHolder
import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 数据源切换处理 * * @author DUCHONG */ public class DynamicDataSourceContextHolder public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class); /** * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本, * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 */ private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>(); /** * 设置数据源的变量 */ public static void setDateSourceType(String dsType) log.info("切换到数据源", dsType); CONTEXT_HOLDER.set(dsType); /** * 获得数据源的变量 */ public static String getDateSourceType() return CONTEXT_HOLDER.get(); /** * 清空数据源变量 */ public static void clearDateSourceType() CONTEXT_HOLDER.remove();
3.3、继承AbstractRoutingDataSource
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import javax.sql.DataSource; import java.util.Map; /** * 动态数据源 * * @author DUCHONG */ public class DynamicDataSource extends AbstractRoutingDataSource public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) super.setDefaultTargetDataSource(defaultTargetDataSource); super.setTargetDataSources(targetDataSources); super.afterPropertiesSet(); @Override protected Object determineCurrentLookupKey() return DynamicDataSourceContextHolder.getDateSourceType();
3.4、定义切面
import com.starfast.admin.common.annotation.DataSource; import com.starfast.admin.datasource.DynamicDataSourceContextHolder; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * 多数据源处理 * @author DUCHONG */ @Aspect @Order(1) @Component public class DataSourceAspect protected Logger logger = LoggerFactory.getLogger(getClass()); @Pointcut("@annotation(com.duchong.common.annotation.DataSource)") public void dsPointCut() @Around("dsPointCut()") public Object around(ProceedingJoinPoint point) throws Throwable MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); DataSource dataSource = method.getAnnotation(DataSource.class); if (null!=dataSource) DynamicDataSourceContextHolder.setDateSourceType(dataSource.value().name()); try return point.proceed(); finally // 销毁数据源 在执行方法之后 DynamicDataSourceContextHolder.clearDateSourceType();
3.5、@Configuration
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import com.starfast.admin.common.enums.DataSourceType; import com.starfast.admin.datasource.DynamicDataSource; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; /** * druid 配置多数据源 * * @author DUCHONG */ @Configuration public class DruidConfig @Bean @ConfigurationProperties("spring.datasource.druid.master") public DataSource masterDataSource() return DruidDataSourceBuilder.create().build(); @Bean @ConfigurationProperties("spring.datasource.druid.slave") @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true") public DataSource slaveDataSource() return DruidDataSourceBuilder.create().build(); @Bean(name = "dynamicDataSource") @Primary public DynamicDataSource dataSource() Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource()); targetDataSources.put(DataSourceType.TREEBEAR.name(), slaveDataSource()); return new DynamicDataSource(masterDataSource(), targetDataSources);
3.6、使用
需要切换数据源的方法上加
@DataSource(value = DataSourceType.SLAVE)
结束。
以上是关于springboot项目自定义注解实现的多数据源切换的主要内容,如果未能解决你的问题,请参考以下文章
实现SpringBoot项目的多数据源配置的两种方式(dynamic-datasource-spring-boot-starter和自定义注解的方式)