前言
此次配置使用Druid数据源
1、pom文件
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
<!-- aspect -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<!-- oracle驱动1 此驱动不需要授权 -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.4.0-atlassian-hosted</version>
</dependency>
<!-- oracle驱动2 此驱动需要授权 -->
<!-- <dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.1.0</version>
</dependency> -->
2、application.yml
spring:
datasource:
druid:
first:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/liujianming?characterEncoding=utf-8&serverTimezone=Hongkong&useSSL=true&zeroDateTimeBehavior=convertToNull
username: root
password: 123456
second:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&serverTimezone=Hongkong&useSSL=true&zeroDateTimeBehavior=convertToNull
username: root
password: 123456
# Oracle也可以配置
#third:
# type: com.zaxxer.hikari.HikariDataSource
# driver-class-name: oracle.jdbc.driver.OracleDriver # oracle数据源需要pom.xml引入oracle驱动
# url: #############
# username: ######
# password: #####
3、DataSource注解
import java.lang.annotation.*;
/**
* @author liujianming
* @version 1.0
* @describe 1、@Target(ElementType.METHOD): 用于描述方法;
* 2、@Retention(RetentionPolicy.RUNTIME):在运行时有效(即运行时保留),编译在class文件中
* 3、@Documented:将注解包含在javadoc文档中
* @date 2022/8/24 8:58
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String name() default "";
}
4、DataSourceNames接口
/**
* @author liujianming
* @version 1.0
* @describe 配置的数据源名称 配置多少个数据源就写几个
* @date 2022/8/24 9:03
*/
public interface DataSourceNames {
String FIRST = "first";
String SECOND = "second";
}
5、DynamicDataSourceConfig配置类
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* @author liujianming
* @version 1.0
* @describe
* @date 2022/8/24 9:04
*/
@Configuration
public class DynamicDataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.druid.first")
public DataSource firstDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.druid.second")
public DataSource secondDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public DynamicDataSource dataSource(DataSource firstDataSource, DataSource secondDataSource) {
Map<Object,Object> targetDataSources = new HashMap<>(16);
targetDataSources.put(DataSourceNames.FIRST,firstDataSource);
targetDataSources.put(DataSourceNames.SECOND,secondDataSource);
return new DynamicDataSource(firstDataSource,targetDataSources);
}
}
6、DynamicDataSource动态数据源
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.Map;
/**
* @author liujianming
* @version 1.0
* @describe 存放DataSource到ThreadLocal中
* @date 2022/8/24 9:23
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object,Object> targetDataSources) {
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return getDataSource();
}
public static void setDataSource(String dataSource) {
CONTEXT_HOLDER.set(dataSource);
}
public static String getDataSource() {
return CONTEXT_HOLDER.get();
}
public static void clearDataSource() {
CONTEXT_HOLDER.remove();
}
}
7、DataSourceAspect
import org.aspectj.lang.ProceedingJoinPoint;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @author liujianming
* @version 1.0
* @describe 数据源切面扫描
* @date 2022/8/24 9:32
*/
@Component
@Aspect
public class DataSourceAspect implements Ordered {
protected Logger logger = LoggerFactory.getLogger(getClass());
@Pointcut("@annotation(com.ljm.thewaytogod.aspect.dynamic.DataSource)")
public void dataSourcePointCut() {
}
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
DataSource dataSource = method.getAnnotation(DataSource.class);
if (dataSource == null) {
DynamicDataSource.setDataSource(DataSourceNames.FIRST);
} else {
DynamicDataSource.setDataSource(dataSource.name());
}
try {
return point.proceed();
} finally {
DynamicDataSource.clearDataSource();
}
}
@Override
public int getOrder() {
return 1;
}
}
8、使用
import com.ljm.thewaytogod.aspect.dynamic.DataSource;
import com.ljm.thewaytogod.aspect.dynamic.DataSourceNames;
import com.ljm.thewaytogod.dao.TestMapper;
import com.ljm.thewaytogod.po.SysUser;
import com.ljm.thewaytogod.po.User;
import com.ljm.thewaytogod.service.TestService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* @author liujianming
* @version 1.0
* @describe
* @date 2022/8/24 15:48
*/
@Service
public class TestServiceImpl implements TestService {
@Resource
private TestMapper testMapper;
@Override
@DataSource // 可以省略,默认是first
public List<SysUser> selectFromFirst() {
return testMapper.selectSysUser();
}
@Override
@DataSource(name = DataSourceNames.SECOND)
public List<User> selectFromSecond() {
return testMapper.selectUser();
}
}