Spring Boot + MyBatis-Plus 读写分离与多 Slave 负载均衡示例
一、项目结构
src/main/java/com/example/demo/
├── config/
│ ├── DataSourceConfig.java # 数据源配置
│ ├── MyBatisPlusConfig.java # MyBatis-Plus配置
├── constant/
│ ├── DataSourceType.java # 数据源类型枚举
├── context/
│ ├── DataSourceContextHolder.java # 数据源上下文
├── aspect/
│ ├── DataSourceAspect.java # 注解驱动的数据源切换
│ ├── DataSourceRouteAspect.java # 自动路由的数据源切换
├── annotation/
│ ├── DataSource.java # 自定义数据源注解
├── loadbalancer/
│ ├── SlaveDataSourceLoadBalancer.java # 从库负载均衡器
├── mapper/
│ ├── UserMapper.java # DAO接口
├── service/
│ ├── UserService.java # 服务接口
│ ├── impl/
│ └── UserServiceImpl.java # 服务实现
├── controller/
│ ├── UserController.java # 控制器
└── DemoApplication.java # 启动类
二、核心代码实现
(一)数据源类型枚举
package com.example.demo.constant;public enum DataSourceType {MASTER,SLAVE_1,SLAVE_2,SLAVE_3
}
(二)数据源上下文
package com.example.demo.context;import com.example.demo.constant.DataSourceType;public class DataSourceContextHolder {private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<>();public static void setDataSource(DataSourceType type) {contextHolder.set(type);}public static DataSourceType getDataSource() {return contextHolder.get();}public static void clearDataSource() {contextHolder.remove();}
}
(三)动态数据源
package com.example.demo.config;import com.example.demo.context.DataSourceContextHolder;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;public class DynamicRoutingDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDataSource();}
}
(四)数据源配置
package com.example.demo.config;import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.example.demo.constant.DataSourceType;
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 DataSourceConfig {@Primary@Bean(name = "masterDataSource")@ConfigurationProperties("spring.datasource.master")public DataSource masterDataSource() {return DruidDataSourceBuilder.create().build();}@Bean(name = "slave1DataSource")@ConfigurationProperties("spring.datasource.slave1")public DataSource slave1DataSource() {return DruidDataSourceBuilder.create().build();}@Bean(name = "slave2DataSource")@ConfigurationProperties("spring.datasource.slave2")public DataSource slave2DataSource() {return DruidDataSourceBuilder.create().build();}@Bean(name = "slave3DataSource")@ConfigurationProperties("spring.datasource.slave3")public DataSource slave3DataSource() {return DruidDataSourceBuilder.create().build();}@Beanpublic DataSource dynamicDataSource() {DynamicRoutingDataSource dynamicDataSource = new DynamicRoutingDataSource();dynamicDataSource.setDefaultTargetDataSource(masterDataSource());Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DataSourceType.MASTER, masterDataSource());targetDataSources.put(