Springboot 多数据源动态切换 以AOP切点方式实现,java技术分享ppt

org.springframework.boot

spring-boot-maven-plugin

然后接下来是application.yml文件:

spring:

datasource:

type: com.alibaba.druid.pool.DruidDataSource

driverClassName: com.mysql.jdbc.Driver

druid:

#第一个数据源连接信息

one:

url: jdbc:mysql://localhost:3306/game_message?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8

username: root

password: root

#第二个数据源连接信息

two:

url: jdbc:mysql://localhost:3306/game_message_cluster?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8

username: root

password: root

#数据库连接池信息

initial-size: 10

max-active: 100

min-idle: 10

max-wait: 60000

pool-prepared-statements: true

max-pool-prepared-statement-per-connection-size: 20

time-between-eviction-runs-millis: 60000

min-evictable-idle-time-millis: 300000

validation-query: SELECT 1 FROM DUAL

test-while-idle: true

test-on-borrow: false

test-on-return: false

stat-view-servlet:

enabled: true

url-pattern: /druid/*

filter:

stat:

log-slow-sql: true

slow-sql-millis: 1000

merge-sql: true

wall:

config:

multi-statement-allow: true

#配置下项目端口

server:

port: 8023

#mybatis扫描文件路径

mybatis:

config-location: classpath:mybatis/mybatis-config.xml

mapper-locations: classpath:mybatis/mapper/*.xml

#将日志文件生成到系统盘路径

logging:

path: F:\logtest\log

#简单设置一下日志等级

level:

web: debug

接下来我们罗列下数据源的名字,这里简单用ONE 、TWO 表示,DataSourceNames.java:

/**

  • @Author : JCccc

  • @CreateTime : 2019/8/28

  • @Description :

**/

public interface DataSourceNames {

String ONE = “ONE”;

String TWO = “TWO”;

}

接着创一个自定义注解,作为aop切点使用,DataSource.java:

import java.lang.annotation.*;

/**

  • @Author : JCccc

  • @CreateTime : 2019/8/28

  • @Description :

**/

@Documented

@Target({ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface DataSource {

String value() default DataSourceNames.ONE; //默认值为ONE,因为后面我们选择配置这个ONE为默认数据库

}

然后是配置AOP切点,DataSourceAspect.java:

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.core.Ordered;

import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

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;

/**

  • @Author : JCccc

  • @CreateTime : 2019/8/28

  • @Description :

**/

@Aspect

@Component

public class DataSourceAspect implements Ordered {

protected Logger logger = LoggerFactory.getLogger(getClass());

/**

  • 切点: 所有配置 DataSource 注解的方法

*/

@Pointcut(“@annotation(com.example.demo.config.DataSource)”)

public void dataSourcePointCut() {}

@Around(“dataSourcePointCut()”)

public Object around(ProceedingJoinPoint point) throws Throwable {

MethodSignature signature = (MethodSignature) point.getSignature();

Method method = signature.getMethod();

DataSource ds = method.getAnnotation(DataSource.class);

// 通过判断 DataSource 中的值来判断当前方法应用哪个数据源

DynamicDataSource.setDataSource(ds.value());

logger.info("AOP切换数据源成功,数据源为: " + ds.value());

logger.info("set datasource is " + ds.value());

try {

return point.proceed();

} finally {

DynamicDataSource.clearDataSource();

logger.info(“clean datasource”);

}

}

@Override

public int getOrder() {

return 1;

}

}

到这里切点AOP的相关配置已经完毕了,接下来到核心的动态数据源配置。

先创建手动切换数据源的核心方法类,DynamicDataSource.java:

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;

import java.util.Map;

/**

  • @Author : JCccc

  • @CreateTime : 2019/8/28

  • @Description :

**/

public class DynamicDataSource extends AbstractRoutingDataSource {

private static final ThreadLocal contextHolder = new ThreadLocal<>();

/**

  • 配置DataSource, defaultTargetDataSource为主数据库

*/

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) {

contextHolder.set(dataSource);

}

public static String getDataSource() {

return contextHolder.get();

}

public static void clearDataSource() {

contextHolder.remove();

}

}

然后是用于读取配置信息多数据源,并将其载入的类,DynamicDataSourceConfig.java:

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 : JCccc

  • @CreateTime : 2019/8/28

  • @Description :

**/

@Configuration

public class DynamicDataSourceConfig {

/**

  • 创建 DataSource Bean

  • */

@Bean

@ConfigurationProperties(“spring.datasource.druid.one”)

public DataSource oneDataSource(){

DataSource dataSource = DruidDataSourceBuilder.create().build();

return dataSource;

}

@Bean

@ConfigurationProperties(“spring.datasource.druid.two”)

public DataSource twoDataSource(){

DataSource dataSource = DruidDataSourceBuilder.create().build();

return dataSource;

}

/**

  • 将数据源信息载入targetDataSources

  • */

@Bean

@Primary

public DynamicDataSource dataSource(DataSource oneDataSource, DataSource twoDataSource) {

Map<Object, Object> targetDataSources = new HashMap<>(2);

targetDataSources.put(DataSourceNames.ONE, oneDataSource);

targetDataSources.put(DataSourceNames.TWO, twoDataSource);

// 如果还有其他数据源,可以按照数据源one和two这种方法去进行配置,然后在targetDataSources中继续添加

System.out.println(“加载的数据源DataSources:” + targetDataSources);

//DynamicDataSource(默认数据源,所有数据源) 第一个指定默认数据库

return new DynamicDataSource(oneDataSource, targetDataSources);

}

}

然后是mapper层,MessageboardMapper.java:

import com.example.demo.pojo.Messageboard;

import org.apache.ibatis.annotations.Mapper;

@Mapper

public interface MessageboardMapper {

Messageboard selectByPrimaryKey(Integer id);

}

然后对应的MessageboardMapper.xml:

<?xml version="1.0" encoding="UTF-8" ?>

id, userName, message

select

from messageboard

where id = #{id,jdbcType=INTEGER}

mybatis-config.xml :

<?xml version="1.0" encoding="UTF-8" ?>

(想了解更多的mybatis配置项,可以看我这篇:https://blog.youkuaiyun.com/qq_35387940/article/details/88049345

接下来是较为关键的,就是service层,简单创建一个DataSourceTestService.java:

/**

  • @Author : JCccc

  • @CreateTime : 2019/8/28

  • @Description :

**/

import com.example.demo.config.DataSource;

import com.example.demo.config.DataSourceNames;

import com.example.demo.mapper.MessageboardMapper;

import com.example.demo.pojo.Messageboard;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

@Service

public class DataSourceTestService {

@Autowired

private MessageboardMapper messageboardMapper;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值