AOP 之 动态数据源
java
package com.github.mengweijin.mybatisplus.demo.DynamicDataSource;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @description 自定义多数据源切换注解
*
* @author Meng Wei Jin
**/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DS {
/**
* 切换数据源名称
*/
String value() default DynamicDataSourceHolder.MASTER;
}
java
package com.github.mengweijin.mybatisplus.demo.DynamicDataSource;
import lombok.Getter;
public class DynamicDataSourceHolder {
public static final String MASTER = "master";
public static final String SLAVE = "slave";
@Getter
public static final ThreadLocal<String> dataSourceThreadLocal = new ThreadLocal<>();
}
java
package com.github.mengweijin.mybatisplus.demo.DynamicDataSource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* @description 动态数据源
*
* @author Meng Wei Jin
**/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSourceThreadLocal().get();
}
}
java
package com.github.mengweijin.mybatisplus.demo.DynamicDataSource;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DynamicDataSourceConfiguration {
@Bean("masterDataSource")
@ConfigurationProperties("spring.datasource.master")
public DataSource masterDataSource() {
return new HikariDataSource();
}
@Bean("slaveDataSource")
@ConfigurationProperties("spring.datasource.slave")
@ConditionalOnProperty(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return new HikariDataSource();
}
@Bean
public DynamicDataSource dataSource() {
Map<Object, Object> targetDataSources = new HashMap<>(2);
targetDataSources.put(DynamicDataSourceHolder.MASTER, masterDataSource());
targetDataSources.put(DynamicDataSourceHolder.SLAVE, slaveDataSource());
DynamicDataSource dataSource = new DynamicDataSource();
dataSource.setDefaultTargetDataSource(masterDataSource());
dataSource.setTargetDataSources(targetDataSources);
return dataSource;
}
}
java
package com.github.mengweijin.mybatisplus.demo.DynamicDataSource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Order(1)
@Component
public class DynamicDataSourceAspect {
@Pointcut("@annotation(com.github.mengweijin.mybatisplus.demo.DynamicDataSource.DS)")
public void dsPointCut() {
}
@Around("dsPointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
DS ds = method.getAnnotation(DS.class);
if (ds != null) {
DynamicDataSourceHolder.getDataSourceThreadLocal().set(ds.value());
}
try {
return joinPoint.proceed();
} finally {
// 在执行方法之后,从 threadLocal 中移除
DynamicDataSourceHolder.getDataSourceThreadLocal().remove();
}
}
}
使用
- 可以添加在类上面,也可以在方法上面。
- 可以指定使用哪个数据源。如果只添加注解而不具体指定,默认使用 DynamicDataSourceHolder.MASTER
java
@DS(DynamicDataSourceHolder.SLAVE)
@Service
public class UserService {
@DS(DynamicDataSourceHolder.SLAVE)
public void add(User user) {
// add user to database
}
}