动态数据源注解
package com.nikooh.server.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String value() default "primary";
}
使用ThreadLocal装配DataSourceType
package com.nikooh.server.aspects;
import com.nikooh.server.enums.DataSourceTypeEnum;
public class DataSourceType {
private static final ThreadLocal<DataSourceTypeEnum> TYPE = new ThreadLocal<>();
public static void setDataBaseType(DataSourceTypeEnum dataSourceType) {
if (dataSourceType == null) {
throw new NullPointerException();
}
TYPE.set(dataSourceType);
}
public static DataSourceTypeEnum getDataSourceType() {
return TYPE.get() == null ? DataSourceTypeEnum.PRIMARY : TYPE.get();
}
public static void clearDataSourceType() {
TYPE.remove();
}
}
配置动态数据源切面
package com.nikooh.server.aspects;
import com.nikooh.server.annotations.DataSource;
import com.nikooh.server.enums.DataSourceTypeEnum;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class DynamicDataSourceAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
@Before("@annotation(dataSource)")
public void changeDataSource(JoinPoint point, DataSource dataSource) {
DataSourceTypeEnum dataSourceType;
if (null == dataSource) {
dataSourceType = DataSourceTypeEnum.PRIMARY;
} else {
String value = dataSource.value();
dataSourceType = DataSourceTypeEnum.parseByValue(value);
}
LOGGER.info(">>>>>>>>>> 当前线程[{}]使用数据源:[{}] <<<<<<<<<<", Thread.currentThread().getId(), dataSourceType.getValue());
DataSourceType.setDataBaseType(dataSourceType);
}
@After("@annotation(dataSource)")
public void restoreDataSource(JoinPoint point, DataSource dataSource) {
LOGGER.info(">>>>>>>>>> 当前线程[{}]已清除数据源:[{}] <<<<<<<<<<", Thread.currentThread().getId(), DataSourceType.getDataSourceType().getValue());
DataSourceType.clearDataSourceType();
}
}
配置类继承AbstractRoutingDataSource类实现切换
package com.nikooh.server.aspects;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceType.getDataSourceType();
}
}
配置动态数据源
package com.nikooh.server.config;
import com.nikooh.server.aspects.DynamicDataSource;
import com.nikooh.server.enums.DataSourceTypeEnum;
import com.nikooh.server.properties.PrimaryDateSourceProperties;
import com.nikooh.server.properties.SecondaryDataSourceProperties;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
@MapperScan(basePackages = "com.nikooh.server.mapper.*", sqlSessionFactoryRef = "sqlSessionFactory")
public class DynamicDataSourceConfig {
@Bean(name = "primaryDataSource")
public DataSource getPrimaryDateSource(PrimaryDateSourceProperties primaryDateSourceProperties) {
return DataSourceBuilder.create(primaryDateSourceProperties.getClass().getClassLoader())
.type(HikariDataSource.class)
.driverClassName(primaryDateSourceProperties.getDriverClassName())
.url(primaryDateSourceProperties.getUrl())
.username(primaryDateSourceProperties.getUserName())
.password(primaryDateSourceProperties.getPassword())
.build();
}
@Bean(name = "secondaryDataSource")
public DataSource getSecondaryDateSource(SecondaryDataSourceProperties secondaryDataSourceProperties) {
return DataSourceBuilder.create(secondaryDataSourceProperties.getClass().getClassLoader())
.type(HikariDataSource.class)
.driverClassName(secondaryDataSourceProperties.getDriverClassName())
.url(secondaryDataSourceProperties.getUrl())
.username(secondaryDataSourceProperties.getUserName())
.password(secondaryDataSourceProperties.getPassword())
.build();
}
@Bean(name = "dynamicDataSource")
public DynamicDataSource dataSource(@Qualifier("primaryDataSource") DataSource primaryDataSource,
@Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
Map<Object, Object> targetDataSource = new HashMap<>();
targetDataSource.put(DataSourceTypeEnum.PRIMARY, primaryDataSource);
targetDataSource.put(DataSourceTypeEnum.SECONDARY, secondaryDataSource);
DynamicDataSource dataSource = new DynamicDataSource();
dataSource.setTargetDataSources(targetDataSource);
dataSource.setDefaultTargetDataSource(primaryDataSource);
return dataSource;
}
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dynamicDataSource);
bean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath*:**/mapper/**/*Mapper.xml"));
return bean.getObject();
}
}
配置读取properties
package com.nikooh.server.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "spring.datasource.primary")
public class PrimaryDateSourceProperties {
private String driverClassName;
private String url;
private String userName;
private String password;
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package com.nikooh.server.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public class SecondaryDataSourceProperties {
private String driverClassName;
private String url;
private String userName;
private String password;
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
resource中的数据源连接信息配置
#----------------------------primary datasource-------------------------
spring.datasource.primary.driverClassName=com.mysql.jdbc.Driver
spring.datasource.primary.url=jdbc:mysql://101.132.238.100:3306/db_nikooh?characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.primary.username=nikooh
spring.datasource.primary.password=199312
#----------------------------secondary datasource-------------------------
spring.datasource.secondary.driverClassName=com.mysql.jdbc.Driver
spring.datasource.secondary.url=jdbc:mysql://101.132.238.100:3306/db_user?characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.secondary.username=nikooh
spring.datasource.secondary.password=199312
spring.main.allow-bean-definition-overriding=true
使用方法