注解方式Spring Boot配置多数据源操作

SpringBoot集成多数据源配置与AOP切换示例
该文详细介绍了如何使用SpringBoot结合mybatis-plus和Druid数据库连接池配置多数据源,并通过AOP实现数据源的动态切换。文中包括了项目依赖设置、YAML配置、数据源容器配置、自动配置类禁用、动态数据源管理、枚举与自定义注解的使用,以及AOP切面类的编写,最后展示了测试用例。

所需资源:

1、springBoot

2、mybatis/mybatis-plus

3、Alibab Druid数据库连接池

4、MySql 数据库

项目结构视图:

共分8步完成,步骤如下:

1、依赖

<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>
<!--数据库连接-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.0.1</version>
</dependency>
<!--aop切面-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<!--数据库连接池-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.14</version>
</dependency>

2、yml基础配置信息

server:
  port: 8088

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    datasource1: #数据源1
      url: jdbc:mysql://localhost:3306/datasource1?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=true
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver

    datasource2: #数据源2
      url: jdbc:mysql://localhost:3306/datasource2?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=true
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver

    druid: # druid数据库连接池的基本初始化属性
      initial-size: 5 # 连接池初始化的大小
      min-idle: 1 # 最小空闲的线程数
      max-active: 20 # 最大活动的线程数


mybatis-plus:
  mapper-locations: classpath:/mapper/*.xml # 配置MyBatis-Plus扫描Mapper文件的位置
  type-aliases-package: com.example.sqlite.entity # 创建别名的类所在的包
  configuration:
    map-underscore-to-camel-case: true # 开启驼峰命名

#sql语句打印
logging:
  level:
    #路径
    com.hua: debug

3、先将两个数据源DataSource 加入IOC容器

package com.hua.config;

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 javax.sql.DataSource;

@Configuration
public class DataSourceConfig {

    @Bean(name = "mysqlDataSource1")
    @ConfigurationProperties(prefix = "spring.datasource.datasource1")
    public DataSource dataSource1(){
        return DruidDataSourceBuilder.create().build();
    }


    @Bean(name = "mysqlDataSource2")
    @ConfigurationProperties(prefix = "spring.datasource.datasource2")
    public DataSource dataSource2(){
        return DruidDataSourceBuilder.create().build();
    }
}

@ConfigurationProperties注解用于将YAML中指定的数据创建成指定的对象,但是,YAML中的数据必须要与对象对象中的属性同名,不然无法由Spring Boot完成赋值。 

4、禁掉Spring Boot的数据源自动配置类

package com.hua;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@MapperScan("com.hua.mapper")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
        System.out.println("Hello word!");
    }
}

在启动类上声明需要禁用的自动配置类:exclude = {DataSourceAutoConfiguration.class} 

5、 重写DataSource动态分配类

package com.hua.config;

import com.hua.constant.DataSourceType;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Primary
@Component
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();
    }
}

 @Primary注解用于帮助我们确定3个DataSource中加载哪个类(IOC中对于DataSource有3个来源,只加载有@Primary注解的)

 6、定义枚举类和自定义注解,并开启aop支持

package com.hua.constant;

public enum DataSourceType {

    MYSQL_DATASOURCE1,

    MYSQL_DATASOURCE2,

}
package com.hua.constant;

import java.lang.annotation.*;

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {

    DataSourceType value() default DataSourceType.MYSQL_DATASOURCE1;
}
package com.hua;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@MapperScan("com.hua.mapper")
@EnableAspectJAutoProxy //开启Spring Boot对AOP的支持
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
        System.out.println("Hello word!");
    }
}

7、 定义注解的切面类

package com.hua.config;

import com.hua.constant.TargetDataSource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
@Aspect
@Slf4j
public class TargetDataSourceAspect {

    @Before("@within(com.hua.constant.TargetDataSource) || @annotation(com.hua.constant.TargetDataSource)")
    public void beforeNoticeUpdateDataSource(JoinPoint 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());
    }
    
}

8、 测试

package com.hua.collection;

import com.hua.bean.HotelBean;
import com.hua.bean.HuikeBean;
import com.hua.constant.DataSourceType;
import com.hua.constant.TargetDataSource;
import com.hua.mapper.MyMapper;
import com.hua.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/jk")
public class MyCollection {

    @Autowired
    private MyService myService;

    @Autowired
    private MyMapper myMapper;

    @TargetDataSource(value = DataSourceType.MYSQL_DATASOURCE1)
    @GetMapping("/selectAll")
    public Object getAll() {
        // 数据处理
        List<OneBean> hotelBeans = myService.selectAll();
        return hotelBeans;
    }

    @TargetDataSource(value = DataSourceType.MYSQL_DATASOURCE2)
    @GetMapping("/data2")
    public Object getAll2() {
        // 数据处理
        List<TwoBean> huikeBeans = myMapper.selectAll2();
        return huikeBeans;
    }
}

大佬完整的参考连接:

Spring Boot配置多数据源的四种方式_springboot配置多数据源_中国胖子风清扬的博客-优快云博客

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值