spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
slave1:
filters: stat
driver-class-name: oracle.jdbc.OracleDriver
url: jdbc:oracle:thin:@127.0.0.1:1521:orcl
username: root
password: root
master:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/aliyun-jdy?characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=UTC
username: root
password: root
package com.xxx.common;
public class DataSourceContextHolder {
public static final String MASTER = "master";
public static final String SLAVE_1 = "slave1";
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDataSource(String name) {
contextHolder.set(name);
}
public static String getDataSource() {
return contextHolder.get();
}
public static void cleanDataSource() {
contextHolder.remove();
}
}
package com.xxx.common;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSource();
}
}
package com.xxx.common;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
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;
@Configuration
public class MultipleDateSourceConfig {
@Bean(DataSourceContextHolder.MASTER)
@ConfigurationProperties(prefix = "spring.datasource.druid.master")
public DataSource createMasterDataSource() {
return new DruidDataSource();
}
@Bean(DataSourceContextHolder.SLAVE_1)
@ConfigurationProperties(prefix = "spring.datasource.druid.slave1")
public DataSource createSlave1DataSource() {
return new DruidDataSource();
}
@Bean
@Primary
public DataSource createDynamicDataSource(@Qualifier(DataSourceContextHolder.MASTER) DataSource master, @Qualifier(DataSourceContextHolder.SLAVE_1) DataSource slave1) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setDefaultTargetDataSource(master);
Map<Object, Object> map = new HashMap<>();
map.put(DataSourceContextHolder.MASTER, master);
map.put(DataSourceContextHolder.SLAVE_1, slave1);
dynamicDataSource.setTargetDataSources(map);
return dynamicDataSource;
}
}
package com.xxx.annotation;
import com.dhht.web.common.DataSourceContextHolder;
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 DataSource {
String value() default DataSourceContextHolder.MASTER;
}
package com.xxx.common;
import com.dhht.web.annotation.DataSource;
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.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.sql.SQLException;
@Aspect
@Component
public class DynamicDataSourceAspect {
@Resource
protected ApplicationContext applicationContext;
private Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
@Pointcut(value = "@target(org.springframework.stereotype.Service) && @annotation(com.dhht.web.annotation.DataSource)")
public void dynamicDataSourcePointCut() {
}
@Before(value = "dynamicDataSourcePointCut()")
public void switchDataSource(JoinPoint joinPoint) throws Throwable {
DataSource dataSource = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(DataSource.class);
if ((null == dataSource)) {
return;
}
logger.info("切换数据源为**:{}", dataSource.value());
DataSourceContextHolder.setDataSource(dataSource.value());
}
@After(value = "dynamicDataSourcePointCut()")
public void after() {
DataSourceContextHolder.cleanDataSource();
logger.info("再次切换数据源为:master");
DataSourceContextHolder.setDataSource("master");
}
@Pointcut("execution(* com.dhht..service..*.*(..))")
public void pointCut() {
}
@Before("pointCut()")
public void before(JoinPoint joinPoint) throws SQLException {
javax.sql.DataSource bean = applicationContext.getBean(javax.sql.DataSource.class);
logger.info("current target services=" + joinPoint.getTarget().toString());
logger.info("current tx datasource=" + bean.getClass().getName());
return;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」