欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Springboot+aop實現(xiàn)配置多數(shù)據(jù)源的示例代碼

 更新時間:2024年11月21日 09:01:07   作者:王五周八  
本文介紹了如何使用SpringAOP和注解實現(xiàn)動態(tài)數(shù)據(jù)源切換,通過自定義注解和ThreadLocal存儲數(shù)據(jù)上下文信息,重寫AbstractRoutingDataSource類并使用自定義切面來實現(xiàn)動態(tài)數(shù)據(jù)源的切換,感興趣的可以了解一下

前言

? 這是我司在對于動態(tài)數(shù)據(jù)源的一個處理方法,采用動態(tài)加載數(shù)據(jù)庫信息實現(xiàn)動態(tài)數(shù)據(jù)源的切換。通過使用Spring AOP + 注解來替換當前線程ThreadLocal中的值,并且通過重寫AbstractRoutingDataSource類重寫determineCurrentLookUpKey()方法,實現(xiàn)動態(tài)數(shù)據(jù)源切換,滿足功能實現(xiàn)的代碼0侵入性,并且高度解耦,實現(xiàn)可拔插功能效果

1、添加依賴(本項目是一個springboot項目)

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.5.2</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-core</artifactId>
    <version>3.5.1</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.9</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.22</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.32</version>
    <scope>runtime</scope>
</dependency>

2、定義數(shù)據(jù)庫類型枚舉類(enum)

/**
 * 數(shù)據(jù)庫配置名字字段
 * @author zh
 * @data 17點14分
 *
 */
public enum DBTypeEnum {
    cs1db("cs1-db"), cs2db("cs2-db");

    private String value;

    DBTypeEnum(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

枚舉主要是用于簡化if-else語句。

3、定義注解(annotation)

/**
 * @author zh
 * @data 17點18分
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DataSourceSwitch {
    /****
     * 順便設(shè)置下默認數(shù)據(jù)源
     * @return
     */
    DBTypeEnum value() default DBTypeEnum.cs1db;
}

定義DataSourceSwitch注解,默認數(shù)據(jù)源為cs1db(數(shù)據(jù)庫一)。

4、編寫ThreadLocal存儲數(shù)據(jù)上下文信息

/**
 * @author zh
 */
public class DbContextHolder {
    private static final ThreadLocal contextHolder = new ThreadLocal<>();
    /**
     * 設(shè)置數(shù)據(jù)源
     * @param dbTypeEnum
     */
    public static void setDbType(DBTypeEnum dbTypeEnum) {
        contextHolder.set(dbTypeEnum.getValue());
    }

    /**
     * 取得當前數(shù)據(jù)源
     * @return
     */
    public static String getDbType() {
        return (String) contextHolder.get();
    }

    /**
     * 清除上下文數(shù)據(jù)
     */
    public static void clearDbType() {
        contextHolder.remove();
    }
}

工具類DbContextHolder用于存儲數(shù)據(jù)名上下文。

5、獲取數(shù)據(jù)源信息

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

/**
 * @author  zh
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    /**
     * 取得當前使用哪個數(shù)據(jù)源
     * @return
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return DbContextHolder.getDbType();
    }
}

工具類DynamicDataSource繼承AbstractRoutingDataSource重寫determineCurrentLookupKey()方法,從工具類DbContextHolder中獲取當前數(shù)據(jù)源信息。

6、自定義切面(Aspect)

/**
 *  @author zh
 *  數(shù)據(jù)源AOP注解實現(xiàn)
 */
@Component
@Aspect
@Order(-100)
public class DataSourceSwitchAspect {

    private Logger log= LoggerFactory.getLogger(DataSourceSwitchAspect.class);

    @Pointcut("execution(* com.zh.cn.business.cs1db..*.*(..))")
    private void cs1dbAspect() {
    }

    @Pointcut("execution(* com.zh.cn.business.cs2db..*.*(..))")
    private void cs2dbAspect() {
    }
    
    @Before( "cs1dbAspect()" )
    public void basic(JoinPoint joinPoint) {
        //log.info("切換到cs1db 數(shù)據(jù)源...");
        setDataSource(joinPoint, DBTypeEnum.cs1db);
    }

    @Before("cs2dbAspect()" )
    public void order (JoinPoint joinPoint) {
        //log.info("切換到cs2db 數(shù)據(jù)源...");
        setDataSource(joinPoint,DBTypeEnum.cs2db);
    }

    /**
     * 添加注解方式,如果有注解優(yōu)先注解,沒有則按傳過來的數(shù)據(jù)源配置
     * @param joinPoint
     * @param dbTypeEnum
     */
    private void setDataSource(JoinPoint joinPoint, DBTypeEnum dbTypeEnum) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        DataSourceSwitch dataSourceSwitch = methodSignature.getMethod().getAnnotation(DataSourceSwitch.class);
        if (Objects.isNull(dataSourceSwitch) || Objects.isNull(dataSourceSwitch.value())) {
            DbContextHolder.setDbType(dbTypeEnum);
        }else{
           // log.info("根據(jù)注解來切換數(shù)據(jù)源,注解值為:"+dataSourceSwitch.value());
            switch (dataSourceSwitch.value().getValue()) {
                case "cs1-db":
                    DbContextHolder.setDbType(DBTypeEnum.cs1db);
                    break;
                case "cs2-db":
                    DbContextHolder.setDbType(DBTypeEnum.cs2db);
                    break;
                default:
                    DbContextHolder.setDbType(dbTypeEnum);
            }
        }
    }
}

通過springAop自定義切面,切入點在* com.zh.cn.business.cs2db..*.*(..)),表示切入點在com.zh.cn.business.cs2db包下的任意子包、任意方法和任意返回值,并通過setDataSource()方法設(shè)置工具類DbContextHolder中數(shù)據(jù)源信息。

7、配置數(shù)據(jù)源信息

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.baomidou.mybatisplus.generator.config.rules.DbType;
import com.zh.cn.Utils.DynamicDataSource;
import com.zh.cn.constants.DBTypeEnum;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
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 org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 加載DataSource
 */
@Configuration
@MapperScan({"com.zh.cn.**.mapper"})
public class MybatisPlusConfig {

    /**
     * mapper-plus分頁插件<br>
     * 文檔:http://mp.baomidou.com<br>
     */
   /* @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        //paginationInterceptor.setLocalPage(true);// 開啟 PageHelper 的支持
        return paginationInterceptor;
    }*/
   @Bean
   public MybatisPlusInterceptor mybatisPlusInterceptor() {
      MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
      interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
      //樂觀鎖
      interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
      return interceptor;
   }


    @Bean(name = "cs1db")
    @ConfigurationProperties(prefix = "spring.datasource.druid.cs1-db" )
    public DataSource cs1db () {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "cs2db")
    @ConfigurationProperties(prefix = "spring.datasource.druid.cs2-db" )
    public DataSource cs2db () {
        return DruidDataSourceBuilder.create().build();
    }

   /**
     * 動態(tài)數(shù)據(jù)源配置
     * @return
     */
    @Bean
    @Primary
    public DataSource multipleDataSource (@Qualifier("cs1db") DataSource cs1db,
                                          @Qualifier("cs2db") DataSource cs2db){
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map< Object, Object > targetDataSources = new HashMap<>();
        targetDataSources.put(DBTypeEnum.cs1db.getValue(), cs1db );
        targetDataSources.put(DBTypeEnum.cs2db.getValue(), cs2db);

        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(cs1db);//指定默認
        return dynamicDataSource;
    }

    @Bean("sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(multipleDataSource(cs1db(),cs2db()));

        sqlSessionFactory.setMapperLocations(new 	PathMatchingResourcePatternResolver().getResources("classpath*:/mapper/*/*Mapper.xml"));

        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setJdbcTypeForNull(JdbcType.NULL);
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setCacheEnabled(false);
        sqlSessionFactory.setConfiguration(configuration);
        sqlSessionFactory.setPlugins(new Interceptor[]{
            mybatisPlusInterceptor()
        });
        return sqlSessionFactory.getObject();
    }


}

通過覆蓋默認的DataSource進行加載動態(tài)數(shù)據(jù)源的配置信息,通過**multipleDataSource()方法設(shè)置數(shù)據(jù)源,最后通過sqlSessionFactory()**設(shè)置數(shù)據(jù)源的最終加載

8、編寫配置文件

spring:
  datasource:
      type: com.alibaba.druid.pool.DruidDataSource
      cs1-db:
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/short-chain?useUnicode=true&characterEncoding=UTF-8
        username: root
        password: 
        initialSize: 10
        minIdle: 20
        maxActive: 100
        maxWait: 60000
      cs2-db:
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/short-chain?useUnicode=true&characterEncoding=UTF-8
        username: root
        password: 
        initialSize: 10
        minIdle: 20
        maxActive: 100
        maxWait: 60000
      	maxActive: 100
        maxWait: 60000

到此這篇關(guān)于Springboot+aop實現(xiàn)配置多數(shù)據(jù)源的示例代碼的文章就介紹到這了,更多相關(guān)Springboot aop多數(shù)據(jù)源內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • 詳解基于redis實現(xiàn)分布式鎖

    詳解基于redis實現(xiàn)分布式鎖

    系統(tǒng)的不斷擴大,分布式鎖是最基本的保障。與單機的多線程不一樣的是,分布式跨多個機器。線程的共享變量無法跨機器。本文將介紹基于redis實現(xiàn)分布式鎖。
    2021-06-06
  • Java設(shè)計模式之單例模式詳解

    Java設(shè)計模式之單例模式詳解

    這篇文章主要為大家詳細介紹了Java設(shè)計模式之單例模式的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • java跳出多重循環(huán)的三種實現(xiàn)方式

    java跳出多重循環(huán)的三種實現(xiàn)方式

    文章主要介紹了Java中跳出多重循環(huán)的三種方式:使用`break`配合標簽、在布爾表達式中添加判斷變量、以及使用`try-catch`制造異常,每種方式都有具體的代碼示例,并輸出了相應(yīng)的執(zhí)行結(jié)果
    2025-01-01
  • Java實現(xiàn)線程按序交替執(zhí)行的方法詳解

    Java實現(xiàn)線程按序交替執(zhí)行的方法詳解

    這篇文章主要為大家詳細介紹了Java如何實現(xiàn)線程按序交替執(zhí)行,文中的示例代碼講解詳細,對我們了解線程有一定幫助,需要的可以參考一下
    2022-10-10
  • Java中的Spring?如何處理循環(huán)依賴

    Java中的Spring?如何處理循環(huán)依賴

    這篇文章主要介紹了Java中的Spring?如何處理循環(huán)依賴,依賴指的是Bean與Bean之間的依賴關(guān)系,循環(huán)依賴指的是兩個或者多個Bean相互依賴,關(guān)于更多Spring?處理循環(huán)依賴的詳情,需要的朋友可以參考下面文章具體內(nèi)容
    2022-05-05
  • 最新評論