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 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 configHolder = new ConcurrentHashMap();
public static Map 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包到处部署,方便了日常开发部署,提升工作效率,希望能帮助到有需要人。