pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.test</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<lombok.version>1.16.18</lombok.version>
<spring.boot.version>2.0.4.RELEASE</spring.boot.version>
<mysql.version>5.1.47</mysql.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<!--<exclusions>-->
<!--<exclusion>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-logging</artifactId>-->
<!--</exclusion>-->
<!--</exclusions>-->
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<version>${spring.boot.version}</version>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--事务-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.7.3</version>
</dependency>
<!--ORM框架beetsql-->
<!--<dependency>-->
<!--<groupId>com.ibeetl</groupId>-->
<!--<artifactId>beetlsql</artifactId>-->
<!--<version>2.13.5.RELEASE</version>-->
<!--</dependency>-->
<!--ORM框架mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
<!--<scope>runtime</scope>-->
</dependency>
<!-- HikariCP数据库连接池 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<!--lombok 配合idea插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!--<!–log4j2日志–>-->
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-log4j2</artifactId>-->
<!--<version>2.0.4.RELEASE</version>-->
<!--</dependency>-->
<!--<!– log4j2全局异步打印需要disruptor依赖–>-->
<!--<dependency>-->
<!--<groupId>com.lmax</groupId>-->
<!--<artifactId>disruptor</artifactId>-->
<!--<version>3.4.2</version>-->
<!--</dependency>-->
<!--mybatis分页-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<!--阿里云短信服务-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.3</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-ecs</artifactId>
<version>4.17.6</version>
</dependency>
<!--emoji -->
<dependency>
<groupId>com.vdurmont</groupId>
<artifactId>emoji-java</artifactId>
<version>5.1.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<!--<resources>-->
<!--<resource>-->
<!--<directory>src/main/resources</directory>-->
<!--<includes>-->
<!--<include>**/*.yml</include>-->
<!--</includes>-->
<!--</resource>-->
<!--<resource>-->
<!--<directory>src/main/resources/mapper</directory>-->
<!--<includes>-->
<!--<include>**/*.xml</include>-->
<!--</includes>-->
<!--</resource>-->
<!--</resources>-->
</build>
</project>
yml.xml配置
server:
port: 8066
servlet:
context-path:
spring:
datasource:
#数据库连接类型
type: com.zaxxer.hikari.HikariDataSource
master:
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8&autoReconnect=true
username:
password:
hikari:
#最小空闲连接
minimum-idle: 5
idle-timeout: 180000
#最大连接数
maximum-pool-size: 10
auto-commit: true
pool-name: CSO-Hikari-master
max-lifetime: 1800000
connection-timeout: 30000
#连接测试查询
connection-test-query: SELECT 1
slave:
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/test1?characterEncoding=UTF-8&autoReconnect=true
username:
password:
hikari:
#最小空闲连接
minimum-idle: 5
idle-timeout: 180000
#最大连接数
maximum-pool-size: 10
auto-commit: true
pool-name: CSO-Hikari-slave
max-lifetime: 1800000
connection-timeout: 30000
#连接测试查询
connection-test-query: SELECT 1
#logging:
#config: classpath:log4j2.xml
mybatis:
type-aliases-package: com.cso.entity
mapper-locations: classpath:mapper/*.xml
pagehelper:
helper-dialect: mysql
reasonable: true
support-methods-arguments: true
params: count=countsql
启动类注解
// 多数据源 需要移除springBoot默认数据源注入
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
// mybatis注解扫描mapper
@MapperScan(basePackages = "")
// 事务
//@EnableTransactionManagement
public class Application {
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
}
数据源配置类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
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.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DataSourceConfiguration {
private static Logger LOGGER = LoggerFactory.getLogger(DataSourceConfiguration.class);
@Value("${spring.datasource.type}")
private Class<? extends DataSource> dataSourceType;
@Bean(name = "masterDataSource")
@ConfigurationProperties("spring.datasource.master")
public DataSource masterDataSource(){
DataSource masterDataSource = DataSourceBuilder.create().type(dataSourceType).build();
LOGGER.info("======== Master注册成功 ========");
return masterDataSource;
}
@Bean(name = "slaveDataSource")
@ConfigurationProperties("spring.datasource.slave")
public DataSource slaveDataSource(){
DataSource slaveDataSource = DataSourceBuilder.create().type(dataSourceType).build();
LOGGER.info("======== Slave注册成功 ========");
return slaveDataSource;
}
@Bean(name = "myDataSource")
// 当一个接口有多个实现类 指定使用该注解的类
@Primary
public DynamicRoutingDataSource dataSource(){
DataSource masterDataSource = masterDataSource();
DataSource slaveDataSource = slaveDataSource();
Map<Object, Object> dataSources = new HashMap<>();
dataSources.put(DataSourceType.MASTER, masterDataSource);
dataSources.put(DataSourceType.SLAVE, slaveDataSource);
return new DynamicRoutingDataSource(masterDataSource, dataSources);
}
}
动态数据源注入
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.Map;
/**
* Spring boot提供了AbstractRoutingDataSource 根据用户定义的规则选择当前的数据源
* 它的抽象方法 determineCurrentLookupKey() 决定使用哪个数据源。
*/
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
private static Logger LOGGER = LoggerFactory.getLogger(DynamicRoutingDataSource.class);
private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<>();
public DynamicRoutingDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSource){
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSource);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return getDataSourceType();
}
public static void setDataBaseType(DataSourceType dataSourceType){
if(dataSourceType == null) throw new NullPointerException();
contextHolder.set(dataSourceType);
LOGGER.info("设置数据源 {}", dataSourceType);
}
public static DataSourceType getDataSourceType(){
LOGGER.info("使用数据源 {}", contextHolder.get());
return contextHolder.get() == null ? DataSourceType.MASTER : contextHolder.get();
}
public static void clearDataSourceType(){
contextHolder.remove();
}
}
AOP方式使用数据源
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.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @Aspect 定义切面注解
* @Pointcut 定义切面点 注解方式
*/
@Aspect
@Component
@Order(value = 1)
public class DataSourceAspect {
@Pointcut("@annotation(com.annotation.DynamicDataSource)")
public void dataSourcePointCut(){
}
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable{
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
//执行方法前设置使用哪个数据源
DynamicDataSource ds = method.getAnnotation(DynamicDataSource.class);
if(ds == null){
DynamicRoutingDataSource.setDataBaseType(DataSourceType.MASTER);
}else {
DynamicRoutingDataSource.setDataBaseType(ds.type());
}
try{
return point.proceed();
} finally {
DynamicRoutingDataSource.clearDataSourceType();
}
}
}
自定义注解
import com.enums.DataSourceType;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DynamicDataSource {
/**
* 数据源类型
* @return 数据源类型
*/
DataSourceType type();
}
数据源枚举
public enum DataSourceType {
MASTER,
SLAVE
}