SpringBoot自定义注解实现多数据源

前置学习

需要了解 注解、Aop、SpringBoot整合Mybatis的使用。

数据准备

基础项目代码:https://gitee.com/J_look/spring-boot-all-demo

数据库SQL 项目中有提供,修改基本信息即可

行动起来

添加依赖

利用 AOP 可以实现对某些代码的解耦,不需要硬编码编写。

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

开启AOP支持

也可以像图中一样,也开启事务管理器,下文会演示事务失效的问题。

定义枚举

这里定义的枚举,代表我们不同的数据库。

public enum DataSourceType {
MYSQL_DATASOURCE1,
MYSQL_DATASOURCE2,
}

定义数据源管理器

由于本人实力原因,解答不了大家这里的疑惑。大致功能 通过修改本地线程的值,来实现数据源的切换

@Component
@Primary
public class DataSourceManagement extends AbstractRoutingDataSource { public static ThreadLocal<String> flag = new ThreadLocal<>(); /**
* 注入数据源
*/
@Resource
private DataSource mysqlDataSource1;
/**
* 注入数据源
*/
@Resource
private DataSource mysqlDataSource2; public DataSourceManagement() {
flag.set(DataSourceType.MYSQL_DATASOURCE1.name());
} @Override
protected Object determineCurrentLookupKey() {
return flag.get();
} @Override
public void afterPropertiesSet() {
Map<Object, Object> targetDataSource = new ConcurrentHashMap<>();
targetDataSource.put(DataSourceType.MYSQL_DATASOURCE1.name(), mysqlDataSource1);
targetDataSource.put(DataSourceType.MYSQL_DATASOURCE2.name(), mysqlDataSource2);
// 设置数据源来源
super.setTargetDataSources(targetDataSource);
// 设置默认数据源
super.setDefaultTargetDataSource(mysqlDataSource1);
super.afterPropertiesSet();
}
}

自定义注解

@target:表示自定义注解能用在哪里

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
DataSourceType value() default DataSourceType.MYSQL_DATASOURCE1;
}

定义切面类

可以看到,我们的切面类采用的是环绕通知,博主在写这篇文章之前,做过大量测试,也参考过比较多的文章,总结以下几点:

  • 采用前置通知,虽然能实现数据源的切换,但是会导致事务失效。(推荐视频)
  • 采用环绕通知,事务不会失效,但是切换数据源却实现不了。(由Bean的加载顺序导致的,下文中的@Order就可以解决,@Transactional默认级别是最后加载。可以查看日志信息知晓。)
@Component
@Aspect
@Slf4j
@Order(Ordered.LOWEST_PRECEDENCE-1) // Bean加载顺序
public class TargetDataSourceAspect { @Around("@within(TargetDataSource) || @annotation(TargetDataSource)")
public Object beforeNoticeUpdateDataSource(ProceedingJoinPoint joinPoint) {
TargetDataSource annotation = null;
Class<? extends Object> target = joinPoint.getTarget().getClass();
if (target.isAnnotationPresent(TargetDataSource.class)) {
// 判断类上是否标注着注解
annotation = target.getAnnotation(TargetDataSource.class);
log.info("类上标注了注解");
} else {
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
if (method.isAnnotationPresent(TargetDataSource.class)) {
// 判断方法上是否标注着注解,如果类和方法上都没有标注,则报错
annotation = method.getAnnotation(TargetDataSource.class);
log.info("方法上标注了注解");
} else {
throw new RuntimeException("@TargetDataSource注解只能用于类或者方法上, 错误出现在:[" +
target.toString() + " " + method.toString() + "];");
}
}
// 切换数据源
DataSourceManagement.flag.set(annotation.value().name());
Object result = null;
try {
// 执行目标代码
result = joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
return result;
}
}

Service

启动测试类:

import look.word.datasource.service.BookService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest; import javax.annotation.Resource; /**
* @author : look-word
* 2022-10-10 23:11
**/
@SpringBootTest
public class TestBookMapper {
@Resource
private BookService bookService;
@Test
void updatePrice() {
System.out.println(bookService.updatePrice(1, 777));
}
}

观察执行日志可知,数据源的切换实现了,事务也没有失效。

参考文章:

SpringBoot 自定义注解 实现多数据源的更多相关文章

  1. [技术博客] SPRINGBOOT自定义注解

    SPRINGBOOT自定义注解 在springboot中,有各种各样的注解,这些注解能够简化我们的配置,提高开发效率.一般来说,springboot提供的注解已经佷丰富了,但如果我们想针对某个特定情景 ...

  2. java/springboot自定义注解实现AOP

    java注解 即是注释了,百度解释:也叫元数据.一种代码级别的说明. 个人理解:就是内容可以被代码理解的注释,一般是一个类. 元数据 也叫元注解,是放在被定义的一个注解类的前面 ,是对注解一种限制. ...

  3. SpringBoot自定义注解

    1.注解的概念 注解是一种能被添加到java代码中的元数据,类.方法.变量.参数和包都可以用注解来修饰.注解对于它所修饰的代码并没有直接的影响. 2.注解的使用范围 1)为编译器提供信息:注解能被编译 ...

  4. 使用IDEA创建SpringBoot自定义注解

    创建SpringBoot项目 添加组织名 选择web 输入项目名称 创建后目录结构为 使用Spring的AOP先加入Maven依赖 <dependency> <groupId> ...

  5. springboot+自定义注解实现灵活的切面配置

    利用aop我们可以实现业务代码与系统级服务例如日志记录.事务及安全相关业务的解耦,使我们的业务代码更加干净整洁. 最近在做数据权限方面的东西,考虑使用切面对用户访问进行拦截,进而确认用户是否对当前数据 ...

  6. SpringBoot自定义注解、AOP打印日志

    前言 在SpringBoot中使用自定义注解.aop切面打印web请求日志.主要是想把controller的每个request请求日志收集起来,调用接口.执行时间.返回值这几个重要的信息存储到数据库里 ...

  7. SpringBoot 自定义注解

    新增注解类 NotRepeatSubmit.java package com.example.demo.annotation; import java.lang.annotation.ElementT ...

  8. SpringBoot自定义注解+异步+观察者模式实现业务日志保存

    一.前言 我们在企业级的开发中,必不可少的是对日志的记录,实现有很多种方式,常见的就是基于AOP+注解进行保存,但是考虑到程序的流畅和效率,我们可以使用异步进行保存,小编最近在spring和sprin ...

  9. SpringBoot自定义注解@YamlPropertySource加载yml或者yaml文件(扩展了@PropertySource)

    1:概述 SpringBoot的@PropertySource注解只支持加载 properties结尾的文件.当使用@ConfigurationProperties 注解配合@EnableConfig ...

随机推荐

  1. 《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

    接上篇django最基本的一些日常用法,这是第19章笔记,希望在做"动手试一试"的时候可以让自己方便参考. 这一章实现了两个功能: 1.让用户能够添加主题Topic和条目Entry ...

  2. Java学习 (九)基础篇 包机制&JavaDoc

    包机制 为了更好地组织类,Java提供了包机制,用于区别类名的命名空间 包语句的语法为: package pkg[.pkg2[.pkg3...]]; 一般利用公司域名倒置作为包名:com.feng.x ...

  3. C#反射跟特性

    一.什么是反射? 了解反射之前我们必须知道一个概念--元数据.有关程序和程序类型的信息叫做元数据,通俗的解释就是类里面的方法.属性.字段等. 而程序在运行的时候去查看其它程序集的行为就叫做反射.在我们 ...

  4. 移动端实现HTML5 mp3录音踩坑指南:系统播放音量变小、一些机型录音断断续续 之 MediaRecorder和AudioWorklet的终极对决

    目录 H5录音见坑填坑 采用MediaRecorder采集音频 音频格式:WebM和PCM 从WebM封装容器中提取PCM数据 录音的兼容性 困扰已久的H5录音时系统播放音量变小的问题 H5录音见坑填 ...

  5. MySQL启动报:[ERROR] The server quit without updating PID file

    修改配置后MySQL启动不了,报错: [root@localhost mysql]# service mysql restart Starting MySQL...[ERROR] The server ...

  6. 定语从句"介词+which/whom"的用法

    介词+which [例句]My elder sister works in the famous university. She graduated from the famous universit ...

  7. Dart 异步编程(一):初步认识

    由于 Dart 是单线程编程语言,对于进行网络请求和I/O操作,线程将发生阻塞,严重影响依赖于此任务的下一步操作. 通常,在一个阻塞任务之后还有许许多多的任务等待被执行.下一步任务需要上一步任务的结果 ...

  8. 「学习笔记」单调队列优化dp

    目录 算法 例题 最大子段和 题意 思路 代码 修剪草坪 题意 思路 代码 瑰丽华尔兹 题意 思路 代码 股票交易 题意 思路 代码 算法 使用单调队列优化dp 废话 对与一些dp的转移方程,我们可以 ...

  9. 写给前端的 react-native 入门指南

    前言 本文主要介绍 react-native(下称 RN) 的入门, 和前端的异同点 文章不涉及功能的具体实现 选择优势 我们先说说, 为什么很多人会选择使用 RN .他对应的特性和普通 Web 的区 ...

  10. kingbaseES R3 集群配置 SSL

    ​ 案例说明: 本测试是在非生产环境下,在官方没有明确声明支持KingbaseCluster使用ssl的前提下,建议只能在测试环境使用,避免生产环境下直接使用. 数据库版本: TEST=# selec ...