Springboot 多数据源动态切换 以AOP切点方式实现

本文涉及的产品
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用版 2核4GB 50GB
简介: Springboot 多数据源动态切换 以AOP切点方式实现

这篇是Springboot操作多数据源,我采用一贯的优雅方式实现:注解 ,切点的方式实现。


进入主题,


先看看这次案例项目的最终目录结构:


image.png


然后我这次准备的两个不同的数据库(多个也可以),


一个是game_message , 一个是 game_message_cluster 。


首先先看看我们这次用到的jar,pom.xml(相关jar的作用都有相关的注释):


<?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.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</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>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--mysql连接-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--Druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
        </dependency>
        <!--整合mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        <!--AOP-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.9</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>


然后接下来是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:



         


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



         


然后是mapper层,MessageboardMapper.java:



         


然后对应的MessageboardMapper.xml:



         


mybatis-config.xml :


1.


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



         


这里需要认真看,



         


这个注解标记的方法就是告诉当前方法即将切换数据源,所切换的数据源就是通过切点注解传值,方法当被调用时,就会从切点先进入AOP进行数据源切换设置。


最后,写一个简单的接口来进行多数据源操作测试,

我准备的两个数据库里面都有一张叫表messageboard的表,里面的数据不一样:


image.png


然后现在用接口调一下,TestController.java:



         


将项目运行,可以看到控制台打印,数据源已经都加载了:


image.png


用postman调下接口:


image.png


可以看到控制台输出:


image.png


OK,到此。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
26天前
|
Java API
springboot实现aop
springboot实现aop
19 1
|
16天前
|
Java Spring
在Spring Boot中使用AOP实现日志切面
在Spring Boot中使用AOP实现日志切面
|
17天前
|
Java Spring
在Spring Boot中使用AOP实现日志切面
在Spring Boot中使用AOP实现日志切面
|
20天前
|
开发框架 Java 数据库
Spring Boot集成多数据源的最佳实践
Spring Boot集成多数据源的最佳实践
|
16天前
|
XML 监控 Java
如何在Spring Boot中使用AOP
如何在Spring Boot中使用AOP
|
16天前
|
监控 Java Spring
在Spring Boot中使用AOP实现日志记录
在Spring Boot中使用AOP实现日志记录
|
21天前
|
容器
springboot-自定义注解拦截ip aop和ioc
springboot-自定义注解拦截ip aop和ioc
|
23天前
|
Java 测试技术 数据安全/隐私保护
Spring Boot中的AOP编程实践
Spring Boot中的AOP编程实践
|
26天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue的宝鸡文理学院学生成绩动态追踪系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的宝鸡文理学院学生成绩动态追踪系统的详细设计和实现(源码+lw+部署文档+讲解等)
11 0
|
29天前
|
Java Spring
手写SpringBoot(五)之整合AOP
Spring开启aop只需要在任意一个加了@Configuration配置类的上面加上@EnableAspectJAutoProxy注解就行.
15 0