springboot aop实现多数据源 读写分离

实现思路:继承 AbstractRoutingDataSource 实现动态切换(aop对于主从变量进行切换)根据变量key读取对应的数据源实例 必须覆盖SqlSessionFactory 、SqlSessionTemplate 

@Configuration
public class DataSourceConfig {
/**
* 主数据库数据源,存入Spring容器
* 注解@Primary表示主数据源
* @return
*/
@ConfigurationProperties(prefix = "spring.datasource.master")
@Primary
@Bean
public DataSource masterDataSource(){
return DruidDataSourceBuilder.create().build();
}

/**
* 从数据库数据源,存入Spring容器
* @return
*/
@ConfigurationProperties(prefix = "spring.datasource.slave")
@Bean
public DataSource slaveDataSource(){
return DruidDataSourceBuilder.create().build();
}

/**
* 决定最终数据源
* @param masterDataSource
* @param slaveDataSource
* @return
*/
@Bean
public DynamicDataSource targetDataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("slaveDataSource") DataSource slaveDataSource){
//存放主从数据源
Map<Object,Object> targetDataSource = new HashMap<>(2);
//主数据源
targetDataSource.put(DBTypeEnum.MASTER, masterDataSource);
//从数据源
targetDataSource.put(DBTypeEnum.SLAVE, slaveDataSource);
//实现动态切换
DynamicDataSource dynamicDataSource = new DynamicDataSource();
//绑定所有数据源
dynamicDataSource.setTargetDataSources(targetDataSource);
//设置默认数据源
dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
return dynamicDataSource;
}

@Bean
public SqlSessionFactory sessionFactory(@Qualifier("targetDataSource") DataSource dynamicDataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*"));
bean.setDataSource(dynamicDataSource);
return bean.getObject();
}

@Bean
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
}

/***
* 当自定义数据源,用户必须注入,否则事务控制不生效
* @param dataSource
* @return
*/
@Bean
public DataSourceTransactionManager dataSourceTx(@Qualifier("targetDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}

---------------------------------------------------------------------------------------------------------------------------------------------------
public class DynamicDataSource extends AbstractRoutingDataSource {

private Logger logger = LoggerFactory.getLogger(DynamicDataSource.class);

@Override
protected Object determineCurrentLookupKey() {
logger.info("使用数据源:"+DynamicDbUtil.get());
return DynamicDbUtil.get();
}
}
---------------------------------------------------------------------------------------------------------------------------------------------------
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DBType {

DBTypeEnum dbType() default DBTypeEnum.MASTER;

}
public enum DBTypeEnum {
/**
* 主数据库
*/
MASTER,

/**
* 从数据库
*/
SLAVE;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------
@Aspect
@Component
public class DataSourceAopAspect {
private Logger logger = LoggerFactory.getLogger(DataSourceAopAspect.class);

@Pointcut("@annotation(com.cn.datasource.annotation.DBType)")
public void dataSourceAopAspect(){

}

/**
* 配置前置通知,切换数据源为从数据库
*/
@Before("dataSourceAopAspect()")
public void readAdvise(JoinPoint joinPoint){
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
DBType dbTypeAn = method.getAnnotation(DBType.class);
DBTypeEnum dbType = dbTypeAn.dbType();
//先移除
DynamicDbUtil.remove();
//设置数据源
DynamicDbUtil.set(dbType);
logger.info("切换到数据源:"+DynamicDbUtil.get());
}
}
posted @ 2022-05-07 12:54  一个追求未知的人  阅读(235)  评论(0)    收藏  举报