zoukankan      html  css  js  c++  java
  • 一种在【微服务体系】下的【参数配置神器】

    最近工作上遇到了一类需求,就是要对接大量外部系统,而需要对接的外部系统又存在各种环境,比如开发,测试,正式环境,他们的配置不尽相同。

    一般情况下,我们可以通过配置application-dev.yml、application-test.yml、application-prod.yml等springboot配置文件来配置这些参数。

    但是由于我们对接外部系统数量极多,而且不停的在增加,所以如果考虑将外部系统的地址,账户密码配置进yml文件,会导致yml文件爆炸且不太好管控,所以需要思考一个更快捷的办法。

    中间我们考虑将这样的配置写进数据库,但是几个环境的数据库都要分别配置,也挺麻烦的。

    经过思考,我们想出了一个代码配置的办法,这种办法可以让程序员在代码级别自由发挥,不受制于运维,仅供大家参考。

    1.首先增加一个接口,定义若干环境

    /**
     * 代码配置参数神器
     *
     * @author xiaokek
     * @since 2020年5月13日 下午4:01:47
     */
    public interface CoreConfig {
        default Map<String, String> getLocal(){ return Collections.EMPTY_MAP;};
        default Map<String, String> getTest(){ return getLocal();};
        default Map<String, String> getProd(){ return getLocal();};
    }

    2.增加一个配置获取器

    /**
     * 各环境配置参数
     *
     * @author xiaokek
     * @since 2020年5月13日 下午4:02:01
     */
    public class CoreConfigs {
        private final Map<String, String> c;
        
        public CoreConfigs(Map<String, String> c) {
            this.c = c;
        }
        public String getConfig(String key) {
            if(!c.containsKey(key)) {
                throw BizException.error("配置项不存在:"+key);
            }
            return c.get(key);
        }
    
    }

    3.增加一个自动配置

    /**
     * 基于不同环境的配置项
     *
     * @author xiaokek
     * @since 2020年2月27日 下午12:35:27
     */
    @Configuration
    @ConditionalOnBean(CoreConfig.class)
    public class EnvAutoConfiguration implements InitializingBean{
    
        @Bean
        @Profile({
            "local", "my", "dev"
        })
        public CoreConfigs localConfig(List<CoreConfig> cs) {
            Map<String, String> r = new LinkedCaseInsensitiveMap<>();
            for(CoreConfig cc : cs) {
                r.putAll(cc.getLocal());
            }
            return new CoreConfigs(r);
        }
    
        @Bean
        @Profile({
            "test"
        })
        public CoreConfigs testConfig(List<CoreConfig> cs) {
            Map<String, String> r = new LinkedCaseInsensitiveMap<>();
            for(CoreConfig cc : cs) {
                r.putAll(cc.getTest());
            }
            return new CoreConfigs(r);
        }
    
        @Bean
        @Profile({
            "prod"
        })
        public CoreConfigs prodConfig(List<CoreConfig> cs) {
            Map<String, String> r = new LinkedCaseInsensitiveMap<>();
            for(CoreConfig cc : cs) {
                r.putAll(cc.getProd());
            }
            return new CoreConfigs(r);
        }
    
        
        @Autowired(required=false)List<CoreConfig> cs;
        @Override
        public void afterPropertiesSet() throws Exception {
            if(CollectionUtils.isEmpty(cs)) {
                return;
            }
            Set<String> all = null;
            for(CoreConfig cc : cs) {
                check(cc);
                all = check(all, cc.getLocal().keySet(),"local", cc);
            }
            all = null;
            for(CoreConfig cc : cs) {
                all = check(all, cc.getTest().keySet(),"test", cc);
            }
            all = null;
            for(CoreConfig cc : cs) {
                all = check(all, cc.getProd().keySet(),"prod", cc);
            }
            
        }
    
      /**
       以开发环境为准,防止参数漏配检查
      */
    private void check(CoreConfig cc) { int size = (cc.getLocal() == null ? 0: cc.getLocal().size()); if(size != (cc.getSit() == null ? 0: cc.getSit().size())) { throw BizException.error(cc.getClass().getName()+" -test的配置参数缺失, 请检查"); }if(size != (cc.getProd() == null ? 0: cc.getProd().size())) { throw BizException.error(cc.getClass().getName()+" -prod的配置参数缺失, 请检查"); } } private Set<String> check(Set<String> all, Set<String> next, String env, CoreConfig cc) { if(all == null) { all = Sets.newHashSet(); } SetView<String> in = Sets.intersection(all, next); if(in != null && in.size() > 0) { throw BizException.error("发现" +cc.getClass().getName() +" - " +env+"的重复配置键: "+in); } all.addAll(next); return all; } }

    4.上面3个是放在一个配置基础jar包,其他微服务小组可以依赖上述jar包,在自己的工程做自己的配置

    关键的一点来了,这样的配置类,可以有无限个,适合拆分在各自的包里

    @Component
    public class JobParamConfig implements CoreConfig{
        @Override
        public Map<String, String> getLocal() {
            Map<String, String> c = Maps.newHashMap();
            //YY接口
            c.put("xxx.webservice.url", "http://xxxx:9040/xxx.asmx?WSDL");
            
            //XX接口
            c.put("350100.url", "http:/xxxx:4321/ylxwjk/");
            c.put("350100.username", "1_1");
            c.put("350100.password", "2");
            
            return c;
        }
        @Override
        public Map<String, String> getProd() {
            Map<String, String> c = Maps.newHashMap();
            //YY接口
            c.put("xxx.webservice.url", "http://220.xx.xx.xx:9040/xxx.asmx?WSDL");
            
            //XX接口
            c.put("350100.url", "http://10.xx.xxx.xx:8089/ylxwjk/");
            c.put("350100.username", "222");
            c.put("350100.password", "222");
    
            return c;
        }
    }

    5.接下来可以快乐使用参数拉!

    @Resource CoreConfigs c;    
    private String initToken() {
            String body = "{"username":""+c.getConfig("350100.username")+"","password":""+c.getConfig("350100.password")+""}";
            String token = null;
            String json = "";
            try {
                ResponseEntity<String> en = rt.exchange( RequestEntity.post(URI.create(c.getConfig("350100.url")+"/user/login")).contentType(MediaType.APPLICATION_JSON).body(body), String.class);
                json = en.getBody();
                Result<String> r = JsonUtil.fromJson(json, Result.class);
                if(StringUtils.equals(r.getCode(),"200")) {
                    token = r.getData();
                }else {
                    throw BizException.error("身份验证获取token失败!:"+r.getMessage());
                }
            }catch (BizException e) {
                throw e;
            }return token;
        }
  • 相关阅读:
    day25:接口类和抽象类
    vue1
    How the weather influences your mood?
    机器学习实验方法与原理
    How human activities damage the environment
    Slow food
    Brief Introduction to Esports
    Massive open online course (MOOC)
    Online learning in higher education
    Tensorflow Dataset API
  • 原文地址:https://www.cnblogs.com/xiaokek/p/14009712.html
Copyright © 2011-2022 走看看