1. 添加依赖
<!-- Nacos配置中心 -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId><version>2022.0.0.0</version>
</dependency>
<!-- 动态数据源(支持多数据源切换) -->
<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>4.2.0</version>
</dependency>
2. 配置Nacos连接
bootstrap.yml
中配置Nacos服务地址及数据源配置文件:
spring:application:name: dynamic-datasource-democloud:nacos:config:server-addr: 127.0.0.1:8848group: DEFAULT_GROUP# 数据源配置文件ID(需在Nacos控制台提前创建)data-id: datasource-config.yamlfile-extension: yamlrefresh-enabled: true # 开启动态刷新
3. Nacos配置内容
在Nacos控制台创建datasource-config.yaml
文件,内容如下:
datasource:dynamic:primary: master # 默认数据源datasource:master:url: jdbc:mysql://127.0.0.1:3306/master?useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driverslave1:url: jdbc:mysql://127.0.0.1:3306/slave1?useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver
4. 动态数据源配置类
@Configuration
@Slf4j
public class DynamicDataSourceConfig {@Bean@ConfigurationProperties(prefix = "spring.datasource.dynamic")public DataSource dynamicDataSource() {// 自动读取Nacos配置中的datasource节点return new DynamicRoutingDataSource();}// 监听Nacos配置变更,刷新数据源@NacosConfigListener(dataId = "datasource-config.yaml", groupId = "DEFAULT_GROUP")public void onConfigChanged(String newConfig) {log.info("检测到数据源配置变更:{}", newConfig);DynamicDataSourceContextHolder.clear();DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dynamicDataSource();ds.reload(); // 核心:触发数据源重载}
}
5. 数据源上下文管理器
public class DynamicDataSourceContextHolder {private static final ThreadLocal<String> CONTEXT = new ThreadLocal<>();public static void setDataSourceKey(String key) {CONTEXT.set(key);}public static String getDataSourceKey() {return CONTEXT.get();}public static void clear() {CONTEXT.remove();}
}
6. 动态切换实现(AOP切面)
@Aspect
@Component
public class DataSourceAspect {@Pointcut("@annotation(com.example.annotation.DS)")public void dataSourcePointCut() {}@Around("dataSourcePointCut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {MethodSignature signature = (MethodSignature) joinPoint.getSignature();DS ds = signature.getMethod().getAnnotation(DS.class);String oldKey = DynamicDataSourceContextHolder.getDataSourceKey();DynamicDataSourceContextHolder.setDataSourceKey(ds.value());try {return joinPoint.proceed();} finally {DynamicDataSourceContextHolder.setDataSourceKey(oldKey);}}
}
7. 自定义注解@DS
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DS {String value() default "master";
}
8. Service层使用示例
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@DS("master")public void insert(User user) {userMapper.insert(user); // 写入主库}@DS("slave1")public User getById(Long id) {return userMapper.selectById(id); // 从slave1读取}
}