3 disconf在springboot下动态配置各个属性,基于docker环境
在上一篇中,我们在springboot项目中简单使用了disconf的配置功能,这一篇我们主要来详解一下disconf的配置文件的动态配置。来看一下disconf.properties文件# 是否使用远程配置文件# true(默认)会从远程获取配置 false则直接获取本地配置enable.remote.conf=true## 配置服务器的 HOST,用逗号分隔127.0.0.1:80
在上一篇中,我们在springboot项目中简单使用了disconf的配置功能,这一篇我们主要来详解一下disconf的配置文件的动态配置。
来看一下disconf.properties文件
# 是否使用远程配置文件
# true(默认)会从远程获取配置 false则直接获取本地配置
enable.remote.conf=true
#
# 配置服务器的 HOST,用逗号分隔 127.0.0.1:8000,127.0.0.1:8000
#
conf_server_host=nginxhost:80
# 版本, 请采用 X_X_X_X 格式
version=1_0_0_0
# APP 请采用 产品线_服务名 格式
app=test_disconf
# 环境
env=abc
# debug
debug=true
# 忽略哪些分布式配置,用逗号分隔
ignore=
# 获取远程配置 重试次数,默认是3次
conf_server_url_retry_times=1
# 获取远程配置 重试时休眠时间,默认是5秒
conf_server_url_retry_sleep_seconds=1
这里面需要配置的难点在于env在docker的动态配置,打成docker后除了conf_server_host需要设置一下nginxhost的docker link,别的都直接写在那无所谓。
而env的动态配置是个麻烦事,我们希望是只打一个包,在所有环境下都适用,无论是rd、local、online都不用再去修改这个disconf.properties,该怎么做呢?
上一篇官方提供了方法(http://disconf.readthedocs.io/zh_CN/latest/tutorial-client/src/Tutorial9.html),就是通过命令行传入
这对于直接用java -jar 来启动该springboot项目是OK的,但是构建到docker里就不行了,dockerfile是提前写好的,里面已经写死了启动命令了,后期我们只能去修改docker的启动端口什么的,无法再传入上面的java -Ddisconf.XXX参数了(或者会的话告诉我一下,就不用下面的步骤了)。那么怎么在不同的环境下动态设置disconf.env参数呢,在使用同一个docker镜像的情况下。
下面来看看源码,我们来了解一下disconf的配置生效的过程。
首先是ConfigMgr.java
当启动工程后,会进入到该类init方法,这里面是做disconf的配置加载的工作,然后进入DisClientConfig.java
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.baidu.disconf.client.config;
import com.baidu.disconf.client.config.inner.DisInnerConfigAnnotation;
import com.baidu.disconf.client.support.DisconfAutowareConfig;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class DisClientConfig {
protected static final Logger LOGGER = LoggerFactory.getLogger(DisClientConfig.class);
protected static final DisClientConfig INSTANCE = new DisClientConfig();
protected static final String filename = "disconf.properties";
private static final String DISCONF_CONF_FILE_PATH_ARG = "disconf.conf";
private boolean isLoaded = false;
public static final String CONF_SERVER_HOST_NAME = "disconf.conf_server_host";
@DisInnerConfigAnnotation(
name = "disconf.conf_server_host"
)
public String CONF_SERVER_HOST;
private List<String> hostList;
public static final String APP_NAME = "disconf.app";
@DisInnerConfigAnnotation(
name = "disconf.app"
)
public String APP;
public static final String VERSION_NAME = "disconf.version";
@DisInnerConfigAnnotation(
name = "disconf.version",
defaultValue = "DEFAULT_VERSION"
)
public String VERSION = "DEFAULT_VERSION";
@DisInnerConfigAnnotation(
name = "disconf.maintype"
)
public String MAIN_TYPE;
public static final String ENV_NAME = "disconf.env";
@DisInnerConfigAnnotation(
name = "disconf.env",
defaultValue = "DEFAULT_ENV"
)
public String ENV = "DEFAULT_ENV";
private static final String ENABLE_REMOTE_CONF_NAME = "disconf.enable.remote.conf";
@DisInnerConfigAnnotation(
name = "disconf.enable.remote.conf",
defaultValue = "false"
)
public boolean ENABLE_DISCONF = false;
@DisInnerConfigAnnotation(
name = "disconf.debug",
defaultValue = "false"
)
public boolean DEBUG = false;
@DisInnerConfigAnnotation(
name = "disconf.ignore",
defaultValue = ""
)
public String IGNORE_DISCONF_LIST = "";
private Set<String> ignoreDisconfKeySet = new HashSet();
@DisInnerConfigAnnotation(
name = "disconf.conf_server_url_retry_times",
defaultValue = "3"
)
public int CONF_SERVER_URL_RETRY_TIMES = 3;
@DisInnerConfigAnnotation(
name = "disconf.user_define_download_dir",
defaultValue = "./disconf/download"
)
public String userDefineDownloadDir = "./disconf/download";
@DisInnerConfigAnnotation(
name = "disconf.conf_server_url_retry_sleep_seconds",
defaultValue = "2"
)
public int confServerUrlRetrySleepSeconds = 2;
@DisInnerConfigAnnotation(
name = "disconf.enable_local_download_dir_in_class_path",
defaultValue = "true"
)
public boolean enableLocalDownloadDirInClassPath = true;
public static DisClientConfig getInstance() {
return INSTANCE;
}
private DisClientConfig() {
}
public synchronized boolean isLoaded() {
return this.isLoaded;
}
public synchronized void loadConfig(String filePath) throws Exception {
if (!this.isLoaded) {
String filePathInternal = "disconf.properties";
if (filePath != null) {
filePathInternal = filePath;
}
String disconfFilePath = System.getProperty("disconf.conf");
if (disconfFilePath != null) {
filePathInternal = disconfFilePath;
}
try {
DisconfAutowareConfig.autowareConfig(INSTANCE, filePathInternal);
} catch (Exception var5) {
LOGGER.warn("cannot find " + filePathInternal + ", using sys var or user input.");
}
DisconfAutowareConfig.autowareConfigWithSystemEnv(INSTANCE);
this.isLoaded = true;
}
}
public List<String> getHostList() {
return this.hostList;
}
public void setHostList(List<String> hostList) {
this.hostList = hostList;
}
public Set<String> getIgnoreDisconfKeySet() {
return this.ignoreDisconfKeySet;
}
public void setIgnoreDisconfKeySet(Set<String> ignoreDisconfKeySet) {
this.ignoreDisconfKeySet = ignoreDisconfKeySet;
}
}
这里面就是我们在disconf.properties里配置的各个属性,通过自定义注解加载到属性上。
然后进入到DisconfAutowareConfig.java类中,进行对各个属性的赋值。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.baidu.disconf.client.support;
import com.baidu.disconf.client.common.annotations.DisconfFileItem;
import com.baidu.disconf.client.config.inner.DisInnerConfigAnnotation;
import com.baidu.disconf.client.support.utils.ClassUtils;
import com.baidu.disconf.client.support.utils.ConfigLoaderUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class DisconfAutowareConfig {
protected static final Logger LOGGER = LoggerFactory.getLogger(DisconfAutowareConfig.class);
private DisconfAutowareConfig() {
}
private static Properties getProperties(String propertyFilePath) throws Exception {
return ConfigLoaderUtils.loadConfig(propertyFilePath);
}
public static void autowareConfigWithSystemEnv(Object obj) throws Exception {
try {
Field[] fields = obj.getClass().getDeclaredFields();
Field[] arr$ = fields;
int len$ = fields.length;
for(int i$ = 0; i$ < len$; ++i$) {
Field field = arr$[i$];
if (field.isAnnotationPresent(DisInnerConfigAnnotation.class) && !Modifier.isStatic(field.getModifiers())) {
DisInnerConfigAnnotation config = (DisInnerConfigAnnotation)field.getAnnotation(DisInnerConfigAnnotation.class);
String name = config.name();
String value = System.getProperty(name);
field.setAccessible(true);
if (null != value) {
try {
ClassUtils.setFieldValeByType(field, obj, value);
} catch (Exception var10) {
LOGGER.error(String.format("invalid config: %s", name), var10);
}
}
}
}
} catch (Exception var11) {
throw new Exception("error while autowareConfigWithSystemEnv autowire config file", var11);
}
}
private static void autowareConfig(Object obj, Properties prop) throws Exception {
if (null != prop && obj != null) {
try {
Field[] fields = obj.getClass().getDeclaredFields();
Field[] arr$ = fields;
int len$ = fields.length;
for(int i$ = 0; i$ < len$; ++i$) {
Field field = arr$[i$];
if ((field.isAnnotationPresent(DisconfFileItem.class) || field.isAnnotationPresent(DisInnerConfigAnnotation.class)) && !Modifier.isStatic(field.getModifiers())) {
String name;
String value;
if (field.isAnnotationPresent(DisconfFileItem.class)) {
name = field.getName();
value = prop.getProperty(name, (String)null);
} else {
DisInnerConfigAnnotation config = (DisInnerConfigAnnotation)field.getAnnotation(DisInnerConfigAnnotation.class);
name = config.name();
String defaultValue = config.defaultValue();
value = prop.getProperty(name, defaultValue);
if (value.equals(defaultValue) && name != null && name.contains("disconf.")) {
String newName = name.substring(name.indexOf(46) + 1);
value = prop.getProperty(newName, defaultValue);
}
}
field.setAccessible(true);
if (null != value) {
try {
ClassUtils.setFieldValeByType(field, obj, value);
} catch (Exception var12) {
LOGGER.error(String.format("invalid config: %s", name), var12);
}
}
}
}
} catch (Exception var13) {
throw new Exception("error while autowire config file", var13);
}
} else {
throw new Exception("cannot autowareConfig null");
}
}
public static void autowareConfig(Object obj, String propertyFilePath) throws Exception {
Properties prop = getProperties(propertyFilePath);
if (null != prop && obj != null) {
autowareConfig(obj, prop);
} else {
throw new Exception("cannot autowareConfig " + propertyFilePath);
}
}
private static void autowareStaticConfig(Class<?> cls, Properties prop) throws Exception {
if (null == prop) {
throw new Exception("cannot autowareConfig null");
} else {
try {
Field[] fields = cls.getDeclaredFields();
Field[] arr$ = fields;
int len$ = fields.length;
for(int i$ = 0; i$ < len$; ++i$) {
Field field = arr$[i$];
if (field.isAnnotationPresent(DisconfFileItem.class) && Modifier.isStatic(field.getModifiers())) {
field.setAccessible(true);
String name = field.getName();
Object value = prop.getProperty(name, (String)null);
if (value != null) {
ClassUtils.setFieldValeByType(field, (Object)null, String.valueOf(value));
}
}
}
} catch (Exception var9) {
throw new Exception("error while autowire config file", var9);
}
}
}
public static void autowareStaticConfig(Class<?> cls, String propertyFilePath) throws Exception {
Properties prop = getProperties(propertyFilePath);
if (null == prop) {
throw new Exception("cannot autowareConfig " + propertyFilePath);
} else {
autowareStaticConfig(cls, prop);
}
}
}
注意关注这两个方法autowareConfig(Object obj, Properties prop),autowareConfigWithSystemEnv(Object obj),前面那个就是获取disconf.properties里的值,把值赋给变量的。而后面那个就是取系统环境变量的
执行顺序是这样的,先读取disconf.properties里的所有属性,然后赋值,譬如将配置文件里的disconf.env定义的rd取出来,赋给变量env。然后再去读取系统环境变量,System.getProperty(name),如果也有值,就覆盖从properties里读取的值,这样就是官方说的从java命令行输入参数就能直接动态覆盖配置文件。
根据这个特性我们就能来定制env了,对的,就是使用环境变量。我们只需要在项目启动时加载disconf.env的环境变量,就能动态指定env了。在docker下,环境变量是很容易设置的。
下面看代码:
package com.tianyalei.disconf.config;
import com.baidu.disconf.client.DisconfMgrBean;
import com.baidu.disconf.client.DisconfMgrBeanSecond;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* @author wuweifeng wrote on 2017/10/16.
*/
@Configuration
public class DisConfig implements EnvironmentAware {
@Bean(destroyMethod = "destroy")
public DisconfMgrBean getDisconfMgrBean() {
DisconfMgrBean disconfMgrBean = new DisconfMgrBean();
disconfMgrBean.setScanPackage("com.tianyalei.disconf");
return disconfMgrBean;
}
@Bean(destroyMethod = "destroy", initMethod = "init")
public DisconfMgrBeanSecond getDisconfMgrBean2() {
return new DisconfMgrBeanSecond();
}
@Override
public void setEnvironment(Environment environment) {
String env = environment.getProperty("disconf");
if(env != null) {
System.setProperty("disconf.env", env);
}
}
}
系统一启动就会调用setEnvironment方法,我们在这里去获取环境变量disconf,然后调用System.setProperty("disconf.env", env);即可将值赋进去,覆盖配置文件里的了。
这个就是本机配的环境变量,只做个演示。将来部署到docker里,docker设置环境变量更为简单,我们就可以使用同一个docker镜像,然后在测试环境和生产环境设置不同的环境变量就OK了。
更多推荐
所有评论(0)