zoukankan      html  css  js  c++  java
  • 借助SpringBoot子容器来实现多数据源工厂

    当我们需要在项目中配置多个Redis、MongoDB、DB、RabbitMQ、Kafka时,往往我们的做法是自定一个配置类,然后参考官方的自动配置类进行部分配置。
    这种做法虽然可以实现多数据源,但是随着版本迭代,可能兼容性不太好。

    下面介绍如果利用Spring Boot 子容器 (Spring 工厂)来创建多数据源的思路。

    思路

    构建一个轻量级的spring boot容器,将主容器的配置信息,截取前缀,以命令行参数的形式传入,并在子容器中实现自动装配,然后再将对象从子容器取出,注入到主容器进行管理。

    代码

    这里以Redis自动配置为例,获取多个StringRedisTemplate工具类,这里只做抛砖引玉,也可以可参考org.springframework.cloud.stream.binder.DefaultBinderFactory#getBinderInstance

    1.RedisConfig.java:创建不同数据源的StringRedisTemplate

    /**
     * <p>
     * RedisConfig
     * <p>
     *
     * @author: kancy
     * @date: 2020/7/13 11:34
     **/
    @Configuration
    public class RedisConfig {
    
        /**
         * 装配一个来自不同数据源的StringRedisTemplate
         * @param springChildContainerProperties
         * @return
         */
        @Bean
        public StringRedisTemplate StringRedisTemplate2(SpringChildContainerProperties springChildContainerProperties){
    
            // 获取主容器的配置属性,并加入到子容器的命令行参数中
            SpringChildContainerProperties.Container container = springChildContainerProperties.getContainer().get("redis2");
            Assert.state(Objects.equals(container.getType(), "redis"), "config is error.");
            // 扁平化环境参数
            ArrayList<String> args = new ArrayList<>();
            Map<String, String> envProperties = new HashMap<>();
            flatten(null, container.getEnvironment(), envProperties);
            for (Map.Entry<String, String> property : envProperties.entrySet()) {
                args.add(String.format("--%s=%s", property.getKey(), property.getValue()));
            }
    
            // 自动装配的类
            Class[] ConfigurationClasses = {RedisAutoConfiguration.class};
            // 创建子容器
            SpringApplicationBuilder springApplicationBuilder = new SpringApplicationBuilder()
                    .sources(ConfigurationClasses)
                    .bannerMode(Banner.Mode.OFF)
                    .logStartupInfo(false)
                    .web(WebApplicationType.NONE);
            // 运行子容器
            ConfigurableApplicationContext redisProducingContext = springApplicationBuilder.run(args.toArray(new String[0]));
    
            // 从子容器中获取RedisConnectionFactory
            RedisConnectionFactory redisConnectionFactory = redisProducingContext.getBean(RedisConnectionFactory.class);
            System.out.println(redisConnectionFactory.toString());
    
            // 从子容器中获取StringRedisTemplate
            StringRedisTemplate redisTemplate = redisProducingContext.getBean(StringRedisTemplate.class);
            System.out.println(redisTemplate.toString());
    
            return redisTemplate;
        }
    
        /**
         * 扁平化
         * @param propertyName
         * @param value
         * @param flattenedProperties
         */
        private void flatten(String propertyName, Object value,
                             Map<String, String> flattenedProperties) {
            if (value instanceof Map) {
                ((Map<Object, Object>) value).forEach((k, v) -> flatten(
                        (propertyName != null ? propertyName + "." : "") + k, v,
                        flattenedProperties));
            }
            else {
                flattenedProperties.put(propertyName, value.toString());
            }
        }
    
    }
    

    2.SpringChildContainerProperties.java:子容器的属性配置类

    /**
     * <p>
     * SpringChildContainerProperties
     * <p>
     *
     * @author: kancy
     * @date: 2020/7/13 13:10
     **/
    @Data
    @Component
    @ConfigurationProperties(prefix = "spring")
    public class SpringChildContainerProperties {
    
        /**
         * 容器
         */
        private Map<String, Container> container = Collections.emptyMap();
    
        @Data
        public static class Container {
            /**
             * 类型
             */
            private String type;
    
            /**
             * 对应的环境变量
             */
            private Map<String, Object> environment = Collections.emptyMap();
        }
    }
    

    3.application.yml:配置文件

    spring:
      application:
        name: application
      redis:
        host: redis.kancy.top
        port: 6379
        password: root
        database: 10
      container:
        redis2:
          type: redis
          environment:
            spring:
              redis:
                password: root
                cluster:
                  nodes: 10.138.60.187:6380,10.138.60.187:6381,10.138.60.187:6382
    
  • 相关阅读:
    anime.js 学习笔记
    swiper 报错 ‘ Can't find variable: Dom7’
    团队管理(二)
    团队管理(一)
    针对数值型数据的相关记录
    react+echarts折柱图实现
    侧边广告之心跳动画
    浅谈尾调用和尾递归
    elementUI 日期选择器获取CRON值
    elementUI 日期选择器之禁止年份事件二
  • 原文地址:https://www.cnblogs.com/kancy/p/13292755.html
Copyright © 2011-2022 走看看