zoukankan      html  css  js  c++  java
  • Springboot应用之配置分离实现方案

    springboot版本 1.5.10.RELEASE
    加载jar外置的配置参数,覆盖jar内置的配置,做到配置与应用的分离。在虚拟化部署时,做到一套代码多个环境部署,提升CICD效率。
    在这里插入图片描述
    下文描述主要步骤
    1、应用程序是properties配置文件,则重写PropertiesPropertySourceLoader

    public class StartUpConfig extends PropertiesPropertySourceLoader {
        @Override
        public PropertySource<?> load(String name, Resource resource, String profile) throws IOException {
            if (profile == null) {
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                /***
                 * 加载jar外置的配置参数,覆盖jar内置的配置,做到配置与应用的分离
                 */
                Properties customFiles = ProfileLoaderConfig.loadFile();
                if(customFiles!=null) {
                    customFiles.entrySet().stream().forEach(item -> {
                        properties.put(item.getKey(),item.getValue());
                    });
                }
                if (!properties.isEmpty()) {
                    return new PropertiesPropertySource(name, properties);
                }
            }
            return null;
            //return super.load(name, resource, profile);
        }
    }
    

    yarn格式,则重写YarnPropertySourceLoader类,重写load接口,同上。
    2、实现自定义配置读取,加载

    public class ProfileLoaderConfig {
        private static Logger logger = LoggerFactory.getLogger(ProfileLoaderConfig.class);
    
        private static Properties loadWarFile() {
            Properties filePropIn = new Properties();
            InputStream input = null;
            try {
                input = Thread.currentThread().getContextClassLoader().getResourceAsStream("config/"+DEFAULT_CONF_FILE_LOCAL);
                if (input == null) {
                    ResourceBundle res = ResourceBundle.getBundle("config.profile");
                    Set<String> keys = res.keySet();
                    for (String key : keys) {
                        filePropIn.put(key, res.getString(key));
                    }
                } else {
                    logger.info(input == null ? "input=null," : "input not null," + "get-input-stream-from:" + DEFAULT_CONF_FILE_LOCAL);
                    filePropIn.load(input);
                }
            } catch (Exception e) {
                logger.error("load",e);
            } finally {
                closeStream(input);
            }
            return filePropIn;
        }
    
        private static Properties loadOutFile(String filePath) {
            Properties filePropOut = new Properties();
            InputStream input = null;
            try {
                input = new FileInputStream(filePath);
                filePropOut.load(input);
                logger.info("外置配置文件{}加载成功", filePath);
                System.out.println("外置配置文件加载成功:"+filePath);
            } catch (Exception e) {
                logger.error("外置配置文件" + filePath + "加载失败!{}", e.getMessage());
                System.out.println("外置配置文件加载失败:"+filePath);
            } finally {
                closeStream(input);
            }
            return filePropOut;
        }
    
        private static void closeStream(InputStream is) {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
    
        private static String DEFAULT_CONF_FILE = File.separator + "wls" + File.separator + "envconfig" + File.separator + "application.properties";
    
        private static String DEFAULT_CONF_FILE_LOCAL = "application.properties";
    
    
        public static Properties loadFile() {
            Properties properties = new Properties();
            properties.putAll(loadWarFile());
            if (properties.containsKey("app.name")) {
                String appName = properties.getProperty("app.name");
                DEFAULT_CONF_FILE = File.separator + "wls" + File.separator + "envconfig" 
                		+ File.separator + appName + File.separator + DEFAULT_CONF_FILE_LOCAL;
            }
            properties.putAll(loadOutFile(DEFAULT_CONF_FILE));
    
            properties.entrySet().stream()
                    .sorted(Comparator.comparing((item)->{return item.getKey().toString();}))
                    .forEach(item->{
                if(item.getKey().toString().indexOf("private")<0 && item.getKey().toString().indexOf("password")<0) {
                    //logger.info("envConfig:{}={}", item.getKey(), item.getValue());
                    System.out.println("envConfig:"+item.getKey()+"="+item.getValue());
                }
                ContextConfig.put(""+item.getKey(),""+item.getValue());
            });
            return properties;
        }
    }
    

    ContextConfig的定义,保存项目所有的配置项。

    public class ContextConfig {
        private static Map<String, String> configHolder = new ConcurrentHashMap();
    
        public static Map<String, String> getConfigMap() {
            return configHolder;
        }
    
        public static String get(String key) {
            return configHolder.get(key);
        }
    
        public static String get(String key, Object defaultVal) {
            if (!configHolder.containsKey(key)) {
                return "" + defaultVal;
            }
            return configHolder.get(key);
        }
    
        public static Long getLong(String key, long def) {
            return Long.valueOf(get(key, def));
        }
    
        public static Double getDouble(String key, double def) {
            return Double.valueOf(get(key, def));
        }
    
        public static Integer getInteger(String key, int def) {
            return Integer.valueOf(get(key, def));
        }
    
        public static Boolean getBoolean(String key, boolean def) {
            return Boolean.valueOf(get(key, def));
        }
    
        public static void put(String key, String val) {
            if (val != null) {
                val = val.trim();
            }
            configHolder.put(key, val);
        }
    
        public static String remove(String key) {
            return configHolder.remove(key);
        }
    
        public static String getAppName() {
            return get("app.name");
        }
    
        public static String getAppEnv() {
            return get("env");
        }
    }
    

    外置文件统一放在/wls/envconfig/{app.name}/[{app.env}]/application.properties文件中。
    外置配置覆写jar内置配置,当然如果有配置中心,则整体优先级:

    配置中心配置 > 外置配置  > jar内置配置
    

    3、配置自定义类作为PropertySource Loader实现类
    resources/META-INF/spring.factories文件添加一些内容:

    # PropertySource Loaders
    org.springframework.boot.env.PropertySourceLoader=
    com.anjiplus.aits.common.config.StartUpConfig
    

    4、应用效果
    在这里插入图片描述
    最终目的:做到配置和应用的分离。各个环境只负责维护环境相关的配置,一个jar包到处部署,方便了日常开发部署,提升工作效率,希望能帮助到有需要人。

  • 相关阅读:
    Linux strip
    有趣的BUG
    GDB watch std::string size
    Redis Cluster Lua
    Double Buffer
    Yarn架构
    天池公交客流预测比赛
    hashmap,ConcurrentHashMap与hashtable的区别
    fail-fast和fail-safe
    常见机器学习算法优缺点
  • 原文地址:https://www.cnblogs.com/coding-now/p/14660597.html
Copyright © 2011-2022 走看看