アーキテクチャの心得について-mybatis複数のデータソースでstartパッケージを使用する


前言:
最近、複数のデータソースが使用され、動的に切り替える必要があるプロジェクトが新しく構築されたので、データソースを切り替えるstarterパッケージを書きました.
spring-boot-starter-multiple-data-source

2つのデータ・ソースを読み書きで分離する例
一.データソースの構成
複数のデータ・ソースの構成
spring:
    datasource:
        master:
          jdbc-url: jdbc:mysql://127.0.0.1:3306/demo1?useUnicode=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8&useSSL=false
          username: xxxxxxxxx
          password: xxxxxxxxx
          driver-class-name: com.mysql.cj.jdbc.Driver
        slave:
          jdbc-url: jdbc:mysql://127.0.0.1:3306/demo2?useUnicode=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8&useSSL=false
          username: xxxxxx
          password: xxxxxx
          driver-class-name: com.mysql.cj.jdbc.Driver

ベースクラス:
DataSourceType.JAvaデータソース列挙クラス
public enum DataSourceType {

    MASTER("master"),
    SLAVE("slave");

    private String dataSource;

    DataSourceType(String dataSource){
        this.dataSource = dataSource;
    }

    public String getDataSource() {
        return dataSource;
    }
}

MybatisConfigクラス:
複数のデータ・ソースをロードし、デフォルトのデータ・ソースはmasterです.
@Configuration
@MapperScan(basePackages = {"**.*Mapper"}) //   DAO
public class MybatisConfig {


    @Bean("master")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource master(){
        return DataSourceBuilder.create().build();
    }

    @Bean("slave")
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSource slave(){
        return DataSourceBuilder.create().build();
    }

    @Bean("dynamicDataSource")
    public DataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map dataSourceMap = new HashMap<>(2);
        dataSourceMap.put(DataSourceType.MASTER.getDataSource(), master());
        dataSourceMap.put(DataSourceType.SLAVE.getDataSource(), slave());
        //   master              
        dynamicDataSource.setDefaultDataSource(master());
        //   master   slave            
        dynamicDataSource.setDataSources(dataSourceMap);
        return dynamicDataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean() throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        //      ,         ,      dynamicDataSource            
        sessionFactory.setDataSource(dynamicDataSource());
        //   Model
        //sessionFactory.setTypeAliasesPackage("com.danke.**.entity");
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        //       
        sessionFactory.setMapperLocations(resolver.getResources("**.*Mapper.xml"));
        return sessionFactory;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        //       ,             @Transactional    
        return new DataSourceTransactionManager(dynamicDataSource());
    }
}

スレッドのセキュリティを保証するコンテキストクラス
public class DynamicDataSourceContextHolder {

    private static final ThreadLocal contextHolder = new ThreadLocal() {
        /**
         *   master      key         key
         */
        @Override
        protected String initialValue() {
            return DataSourceType.MASTER.getDataSource();
        }
    };


    /**
     *      key  ,              
     */
    public static List dataSourceKeys = new ArrayList<>();

    /**
     *      
     * @param key
     */
    public static void setDataSourceKey(String key) {
        contextHolder.set(key);
    }

    /**
     *      
     * @return
     */
    public static String getDataSourceKey() {
        return contextHolder.get();
    }

    /**
     *      
     */
    public static void clearDataSourceKey() {
        contextHolder.remove();
    }

    /**
     *          
     * @param key    key
     * @return
     */
    public static boolean containDataSourceKey(String key) {
        return dataSourceKeys.contains(key);
    }

    /**
     *      keys
     * @param keys
     * @return
     */
    public static boolean addDataSourceKeys(Collection extends Object> keys) {
        return dataSourceKeys.addAll(keys);
    }

}

TargetDataSource.JAva注釈クラス
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {

    /**
     *    key 
     * @return
     */
    DataSourceType value();

}

切面ダイナミック切替データソース
@Slf4j
@Aspect
@Order(-1)
@Component
public class DynamicDataSourceAspect {

    /**
     *      
     * @param point
     * @param targetDataSource
     */
    @Before("@annotation(targetDataSource))")
    public void switchDataSource(JoinPoint point, TargetDataSource targetDataSource) {
        if (!DynamicDataSourceContextHolder.containDataSourceKey(targetDataSource.value().getDataSource())) {
            log.info("    【{}】    ,         【{}】 " + targetDataSource.value());
        } else {
            //      
            DynamicDataSourceContextHolder.setDataSourceKey(targetDataSource.value().getDataSource());
            log.info("     【" + DynamicDataSourceContextHolder.getDataSourceKey()
                    + "】    【" + point.getSignature() + "】");
        }
    }

    /**
     *      
     * @param point
     * @param targetDataSource
     */
    @After("@annotation(targetDataSource))")
    public void restoreDataSource(JoinPoint point, TargetDataSource targetDataSource) {
        //            
        DynamicDataSourceContextHolder.clearDataSourceKey();
        log.info("       【" + DynamicDataSourceContextHolder.getDataSourceKey()
                + "】     【" + point.getSignature() + "】");
    }
}

ここですべての構成が完了しました
適用:
springboot起動クラスに追加する必要があります
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

1つ目:
starterパッケージに、META-INF/springを追加します.factoriesファイル:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
xxx.xxx.xxx.MybatisConfig

プロジェクトに導入されたjarパッケージは、MybatisConfigファイルを自動的にロードします.
2つ目:
MybatisConfigクラス統合starterパッケージのMybatisConfigをプロジェクトに追加
次のコードがあります.
@Configuration
public class MybatisConfig extends xxx.xxx.xxx.MybatisConfig{
}

@TargetDataSourceをメソッドで識別するデータソースの切り替え
    @TargetDataSource(DataSourceType.SLAVE)
    @Override
    public void selectById(Integer id) {
       //  slave   
    }
    
    @TargetDataSource(DataSourceType.MASTER)
    @Override
    public void updateById(String str) {
        //  master   
    }

3つ目:
この方式もspringbootで現在使用されており、構成は一切不要で、注釈のみです.
新しい注釈クラス
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MybatisConfig.class)
public @interface MultipleDataSource {
}

次に起動クラスに注記します
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableDiscoveryClient
@MultipleDataSource//      
public class Application {
  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}