使用面向切面编程 + ThreadLocal + 自定义注解完成动态数据源切换
时间: 2023-07-25 14:46:21 浏览: 119
动态数据源切换可以通过AOP(面向切面编程)和ThreadLocal来实现。其中,ThreadLocal是Java中的一个线程级别的变量,可以在同一个线程中共享数据。自定义注解可以用来标记需要切换数据源的方法。
实现步骤如下:
1. 定义数据源切换注解
```java
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
String value() default "primary";
}
```
2. 定义数据源切换切面
```java
@Aspect
@Component
public class DataSourceAspect {
@Pointcut("@annotation(com.example.demo.annotation.DataSource)")
public void dataSourcePointCut() {
}
@Before("dataSourcePointCut()")
public void before(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
DataSource dataSource = signature.getMethod().getAnnotation(DataSource.class);
if (dataSource != null) {
DynamicDataSourceContextHolder.setDataSource(dataSource.value());
} else {
DynamicDataSourceContextHolder.setDataSource("primary");
}
}
@After("dataSourcePointCut()")
public void after(JoinPoint joinPoint) {
DynamicDataSourceContextHolder.clearDataSource();
}
}
```
3. 定义ThreadLocal存储数据源信息
```java
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDataSource(String dataSource) {
contextHolder.set(dataSource);
}
public static String getDataSource() {
return contextHolder.get();
}
public static void clearDataSource() {
contextHolder.remove();
}
}
```
4. 在数据源配置文件中定义多个数据源
```java
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties("datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@Primary
public DynamicDataSource dataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object, Object> dataSourceMap = new HashMap<>(2);
dataSourceMap.put("primary", primaryDataSource());
dataSourceMap.put("secondary", secondaryDataSource());
dynamicDataSource.setTargetDataSources(dataSourceMap);
dynamicDataSource.setDefaultTargetDataSource(primaryDataSource());
return dynamicDataSource;
}
}
```
5. 在需要切换数据源的方法上添加@DataSource注解
```java
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
@DataSource("primary")
public List<User> listPrimaryUsers() {
return userMapper.listUsers();
}
@Override
@DataSource("secondary")
public List<User> listSecondaryUsers() {
return userMapper.listUsers();
}
}
```
这样,在调用listPrimaryUsers和listSecondaryUsers方法时,就会自动切换到对应的数据源。
阅读全文