最近在做保证金余额查询优化,在项目启动时候需要把余额全量加载到本地缓存,因为需要全量查询所有骑手的保证金余额,为了不影响主数据库的性能,考虑把这个查询走从库。所以涉及到需要在一个项目中配置多数据源,并且能够动态切换。经过一番摸索,完美实现动态切换,记录一下配置方法供大家参考。

设计总体思路

Spring-Boot+AOP方式实现多数据源切换,继承AbstractRoutingDataSource实现数据源动态的获取,在service层使用注解指定数据源。

步骤

一、多数据源配置

在application.properties中,我们的配置是这样的

#主数据源

druid.master.url=jdbc:mysql://url/masterdb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull

druid.master.username=xxx

druid.master.password=123

druid.master.driver-class-name=com.mysql.jdbc.Driver

druid.master.max-wait=5000

druid.master.max-active=100

druid.master.test-on-borrow=true

druid.master.validation-query=SELECT 1

#从数据源

druid.slave.url=jdbc:mysql://url/slavedb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull

druid.slave.username=xxx

druid.slave.password=123

druid.slave.driver-class-name=com.mysql.jdbc.Driver

druid.slave.max-wait=5000

druid.slave.max-active=100

druid.slave.test-on-borrow=true

druid.slave.validation-query=SELECT 1

读取配置

二、动态数据源

spring为我们提供了AbstractRoutingDataSource,即带路由的数据源。继承后我们需要实现它的determineCurrentLookupKey(),该方法用于自定义实际数据源名称的路由选择方法,由于我们将信息保存到了ThreadLocal中,所以只需要从中拿出来即可。

public class DynamicDataSource extends AbstractRoutingDataSource {

private Logger logger = LoggerFactory.getLogger(this.getClass());

@Override

protected Object determineCurrentLookupKey() {

String dataSource = JdbcContextHolder.getDataSource();

logger.info("数据源为{}",dataSource);

return dataSource;

}

}

三. 数据源动态切换类

动态数据源切换是基于AOP的,所以我们需要声明一个AOP切面,并在切面前做数据源切换,切面完成后移除数据源名称。

@Aspect

@Order(1) //设置AOP执行顺序(需要在事务之前,否则事务只发生在默认库中)

@Component

public class DataSourceAspect {

private Logger logger = LoggerFactory.getLogger(this.getClass());

//切点

@Pointcut("execution(* com.xxx.service.*.*(..))")

public void aspect() { }

@Before("aspect()")

private void before(JoinPoint point) {

Object target = point.getTarget();

String method = point.getSignature().getName();

Class> classz = target.getClass();// 获取目标类

Class>[] parameterTypes = ((MethodSignature) point.getSignature())

.getMethod().getParameterTypes();

try {

Method m = classz.getMethod(method, parameterTypes);

if (m != null && m.isAnnotationPresent(MyDataSource.class)) {

MyDataSource data = m.getAnnotation(MyDataSource.class);

logger.info("method :{},datasource:{}",m.getName() ,data.value().getName());

JdbcContextHolder.putDataSource(data.value().getName());// 数据源放到当前线程中

}

} catch (Exception e) {

logger.error("get datasource error ",e);

//默认选择master

JdbcContextHolder.putDataSource(DataSourceType.Master.getName());// 数据源放到当前线程中

}

}

@AfterReturning("aspect()")

public void after(JoinPoint point) {

JdbcContextHolder.clearDataSource();

}

}

四、数据源管理类

public class JdbcContextHolder {

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

public static void putDataSource(String name) {

local.set(name);

}

public static String getDataSource() {

return local.get();

}

public static void clearDataSource() {

local.remove();

}

}

五、数据源注解和枚举

我们切换数据源时,一般都是在调用具体接口的方法前实现,所以我们定义一个方法注解,当AOP检测到方法上有该注解时,根据注解中value对应的名称进行切换。

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface MyDataSource {

DataSourceType value();

}

public enum DataSourceType {

// 主表

Master("master"),

// 从表

Slave("slave");

private String name;

private DataSourceType(String name) {

this.name = name;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

}

六、切点注解

由于我们的动态数据源配置了默认库,所以如果方法是操作默认库的可以不需要注解,如果要操作非默认数据源,我们需要在方法上添加@MyDataSource("数据源名称")注解,这样就可以利用AOP实现动态切换了

@Component

public class xxxServiceImpl {

@Resource

private XxxMapperExt xxxMapperExt;

@MyDataSource(value= DataSourceType.Slave)

public List getAll(){

return xxxMapperExt.getAll();

}

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

java方法嵌套数据源切换_SpringBoot AOP方式实现多数据源切换的方法相关推荐

  1. mysql多数据源切换_Springboot项目实现Mysql多数据源切换的完整实例

    一.分析AbstractRoutingDataSource抽象类源码 关注import org.springframework.jdbc.datasource.lookup.AbstractRouti ...

  2. springboot 多数据源 读写分离 AOP方式

    大家好,我是烤鸭: 今天分享springboot读写分离配置.    环境:  springboot  2.1.0.RELEASE          场景说明,目前的需求是 读数据源 * 2 + 写数 ...

  3. 2 数据源配置_SpringBoot 整合Druid与配置数据源监控

    一:简绍 1.对于数据访问层,无论是SQL还是NOSQL 2.Spring Boot默认采用整合Spring Data的方式进行统一处理 3.添加大量自动配置,屏蔽了很多设置 1.官网描述 二:整合J ...

  4. SpringBoot面向切面编程-用AOP方式管理日志

    面向切面编程 认识AOP AOP(Aspect Oriented Program,面向切面编程)把业务功能分为核心.非核心两部分. 核心业务功能 非核心业务功能 用户登录,增加数据,删除数据 性能统计 ...

  5. java中实现多线程的三种方式

    java中实现多线程的三种方式 1.实现多线程的方法: 在java中实现多线程的两途径:继承Thread类,实现Runable接口(Callable) 2.继承Thread类实现多线程: ​ 继承类T ...

  6. SpringBoot多数据源切换,AOP实现动态数据源切换

    SpringBoot多数据源切换,AOP实现动态数据源切换 操作数据一般都是在DAO层进行处理,可以选择直接使用JDBC进行编程 或者是使用多个DataSource 然后创建多个SessionFact ...

  7. Java开发【Spring之AOP详解(xml--注解->方法增强、事务管理(声明事务的实现))】

    文章目录 引入 一.AOP概述 1.什么是AOP 2.AOP的优势及使用场景 3.AOP实现原理 二.代理模式 1.代理模式概念 2.代理模式分类 3.静态代理演示 定义HouseAgencyComp ...

  8. AOP注解@Before、@AfterReturning拦截单个方法的入参和出参,纯注解方式(附源码下载),解决单个方法不生效问题(一)

    AOP注解@Before.@AfterReturning拦截单个方法的入参和出参,纯注解方式(附源码下载),解决单个方法不生效问题(一) 问题背景 AOP注解@Before.@AfterReturni ...

  9. aop统计请求数量_Spring-Boot+AOP+统计单次请求方法的执行次数和耗时情况-Go语言中文社区...

    本篇结合aop(面向切面编程)的特性,对spring-boot项目下后端开发人员所关心的java代码的性能做了一次简单的统计,比如,前端发了一个post请求(一连串数据的保存),到了后端,首先是指定C ...

最新文章

  1. 公司SAP ERP 项目开始上线切换和最终用户培训了!
  2. php smtp报文_PHP 使用 SMTP 发送邮件教程(PEAR Mail 包)
  3. C/S与B/S系统测试的不同点和相同点
  4. 从angularJS看MVVM
  5. 如何优化你的ERP库存管理系统
  6. VRP基础,命令行基础,文件系统基础,系统管理(2017年12月13日 09:51:51)
  7. 机器人学习笔记(3) 正运动学和逆运动学
  8. 在屏幕上绘制圆形函数
  9. 酷派的新机、心机、心悸
  10. hdu 5745 La Vie en rose 2016多校第二场1012
  11. emlog mysql 设置_EMLOG模板自定义首页
  12. onload 属性的作用
  13. Markdown个人学习记录
  14. 高尔顿的表哥是谁? ^-^ 理解线性与回归---人工智能工作笔记0017
  15. 《星际穿越》初解析——一部空前绝后的史诗科学巨作
  16. IOC-IOC的简单介绍
  17. Powerpoint高级技巧
  18. 通向架构师的道路(第二十六天)漫谈架构与设计文档的写作技巧
  19. python长度转换
  20. C++ Primer Plus P125~P200

热门文章

  1. docker利用Dockerfile来制作镜像
  2. 20145307《信息安全系统设计基础》第十一周学习总结
  3. jquery 表格自动拆分(方便打印)插件-printTable
  4. FIREDAC连接SQLITE乱码的解决
  5. cocos2d-x的定时器
  6. 【Emit基础】如何发射foreach代码?
  7. 高级工作流模式深入业务场景分析(1)——多路合并
  8. java类的加载机制简述
  9. JVM-内存溢出场景模拟
  10. TFLite基础知识