发布于2026-08-19 阅读(0)
扫一扫,手机访问
AbstractRoutingDataSource是Spring框架中的一个抽象类,可以实现多数据源的动态切换和路由,以满足复杂的业务需求和提高系统的性能、可扩展性、灵活性。
1.AbstractRoutingDataSource实现了DataSource接口,作为一个数据源的封装类,负责路由数据库请求到不同的目标数据源

2.该类中定义了一个determineTargetDataSource方法,会获取当前的目标数据源标识符,进而返回真正的数据源;
值得注意的是:其中determineCurrentLookupKey为抽象方法,明显是要让用户自定义实现获取数据源标识的业务逻辑。

3.当系统执行数据库操作之前,会先获取数据源链接,即调用getConnection方法,该类重写的getConnection方法,会获取到真正的目标数据源,进而将数据库操作委托给目标数据源进行处理。

spring:
datasource:
business-master:
url: jdbc:mysql://ip1:3306/xxx
username: c_username
password: p1
business-sla ver:
url: jdbc:mysql://ip2:3306/xxx
username: c_username
password: p2 2.读取yml中的主从数据源配置
@Data
@ConfigurationProperties(prefix = "spring.datasource")
@Component
public class DataSourcePropertiesConfig {
/**
* 主库配置
*/
DruidDataSource businessMaster;
/**
* 从库配置
*/
DruidDataSource businessSla ver;
} 3. 自定义一个动态数据源类,命名为DynamicRoutingDataSource,让它继承自AbstractRoutingDataSource类。然后呢,要重写其中的determineCurrentLookupKey方法,在这里面定义获取目标数据源标识的逻辑。
此处的逻辑为:定义一个DataSourceHolder类,将数据源标识放到ThreadLocal中,当需要时从ThreadLocal中获取。
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
/**
* 获取目标数据源标识
*/
@Override
protected Object determineCurrentLookupKey() {
return DataSourceHolder.getDbName();
}
} public class DataSourceHolder {
/**
* 当前线程使用的 数据源名称
*/
private static final ThreadLocal THREAD_LOCAL_DB_NAME = new ThreadLocal<>();
/**
* 设置数据源名称
*/
public static void setDbName(String dbName) {
THREAD_LOCAL_DB_NAME.set(dbName);
}
/**
* 获取数据源名称,为空的话默认切主库
*/
public static String getDbName() {
String dbName = THREAD_LOCAL_DB_NAME.get();
if (StringUtils.isBlank(dbName)) {
dbName = DbNameConstant.MASTER;
}
return dbName;
}
/**
* 清除当前数据源名称
*/
public static void clearDb() {
THREAD_LOCAL_DB_NAME.remove();
}
} 4.创建一个动态数据源DynamicRoutingDataSource对象,然后将其注入到容器当中。在此过程中,创建了主从两个数据源,对它们进行初始化操作,分别为这两个数据源设置数据源标识,并将它们放置在DynamicRoutingDataSource对象里,方便后续使用。
若为多个数据源,可参考此处进行批量定义。
@Configuration
public class DataSourceConfig {
@Autowired
private DataSourcePropertiesConfig dataSourcePropertiesConfig;
/**
* 主库数据源
*/
public DataSource masterDataSource() throws SQLException {
DruidDataSource businessDataSource = dataSourcePropertiesConfig.getBusinessMaster();
businessDataSource.init();
return businessDataSource;
}
/**
* 从库数据源
*/
public DataSource sla verDataSource() throws SQLException {
DruidDataSource businessDataSource = dataSourcePropertiesConfig.getBusinessSla ver();
businessDataSource.init();
return businessDataSource;
}
/**
* 动态数据源
*/
@Bean
public DynamicRoutingDataSource dynamicRoutingDataSource() throws SQLException {
DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
Map 5.自定义一个注解,指定数据库。
可以将一些常用的查询接口自动路由到读库,以减轻主库压力。
@Documented
@Inherited
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSourceSwitch {
/**
* 数据源名称,默认主库
*/
String dbName() default "master";
} 6.定义一个切面,拦截所有Controller接口,使用DataSourceSwitchRead注解的方法,将统一路由到读库查询
@Aspect
@Component
@Slf4j
public class DataSourceAspect {
/**
* 切库,若为多个从库,可在这里添加负载均衡策略
*/
@Before(value = "execution ( * com.jd.gyh.controller.*.*(..))")
public void changeDb(JoinPoint joinPoint) {
Method m = ((MethodSignature) joinPoint.getSignature()).getMethod();
DataSourceSwitch dataSourceSwitch = m.getAnnotation(DataSourceSwitch.class);
if (dataSourceSwitch == null) {
DataSourceHolder.setDbName(DbNameConstant.MASTER);
log.info("switch db dbName = master");
} else {
String dbName = dataSourceSwitch.dbName();
log.info("switch db dbName = {}", dbName);
DataSourceHolder.setDbName(dbName);
}
}
}
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
4
5
6
7
8
9