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包到处部署,方便了日常开发部署,提升工作效率,希望能帮助到有需要人。
posted on 2019-07-18 09:54 coding-now 阅读(223) 评论(0) 编辑 收藏 举报
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 对象命名为何需要避免'-er'和'-or'后缀
· SQL Server如何跟踪自动统计信息更新?
· AI与.NET技术实操系列:使用Catalyst进行自然语言处理
· 分享一个我遇到过的“量子力学”级别的BUG。
· Linux系列:如何调试 malloc 的底层源码
· C# 中比较实用的关键字,基础高频面试题!
· .NET 10 Preview 2 增强了 Blazor 和.NET MAUI
· Ollama系列05:Ollama API 使用指南
· 为什么AI教师难以实现
· 如何让低于1B参数的小型语言模型实现 100% 的准确率