配置文件设计 - 969251639/study GitHub Wiki
在以前的项目中,定义的常量配置都是同过配置在properties文件中,然后通过spring加载放到System中
<!-- 加载properties文件 -->
<bean id="propertyConfigurer" class="org.sunshine.dcda.basecomponent.file.PropertyPlaceholderConfigurerImpl">
<property name="locations">
<list>
<value>classpath:properties/develop/*.properties</value>
</list>
</property>
</bean>
public class PropertyPlaceholderConfigurerImpl extends PropertyPlaceholderConfigurer {
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props) throws BeansException {
Enumeration<Object> keys = props.keys();
PropertyPlaceHelper pHelper = new PropertyPlaceHelper(props);
while (keys.hasMoreElements()) {
String key = (String) keys.nextElement();
System.setProperty(key, pHelper.getProperty(key));
}
super.processProperties(beanFactory, props);
}
}
然后再定义成常量对外公开
public class xxxConstants {
public static final String XXX = System.getProperty("xxx");
...
}
这样使用不便于配置文件修改后动态加载,所以简单的设计了以下方式
在注册中心启动后,按启动环境加载响应的配置文件到Properties对象中,并启动定时器,监听机器上的properties的修改时间
微服务启动前向注册中心拉去自己服务对应的文件到内存
Properties文件变更后,注册中心根据文件所在的服务名通过mq推送给对应的服务,服务反射加载最新的内容
优点:使用方便,直接和以前一样的使用static直接获取 缺点:注册中心托管配置文件,如有多台注册中心,则文件管理多份;无页面配置,无审核;修改时需要修改服务器上的文件
- 注册中心启动后建立properties文件的修改时间监听
@Component
public class ApplicationStartup implements ApplicationRunner {
private final Logger logger = LoggerFactory.getLogger(ApplicationStartup.class);
private static Map<String, Long> map = new HashMap<String, Long>();
@Autowired
private Environment env;
@Value("${config.path}")
private String configPath;
@Value("${jms.detination.properties}")
private String destination;
@Autowired
private Productor productor;
@Override
public void run(ApplicationArguments args) {
String currentEnv = env.getActiveProfiles()[0];
if(!EnvContants.DEV_ENV.equals(currentEnv)) {//本地环境不需要加载,过滤掉
File file = new File(configPath);
if(!file.exists()) {
return;
}
try {
PropertiesUtils.setEnv(currentEnv);
PropertiesUtils.setConfigPath(configPath.trim());
} catch (Exception e) {
logger.error("load properties fail. path: " + configPath, e);
}
//启动扫描定时器
TimerTask task = new TimerTask() {
@Override
public void run() {
//扫描configPath目录下所有properties文件,获取修改时间
try {
scanFile(file);
} catch (IOException e) {
logger.error("load properties fail. file: " + file.getAbsolutePath(), e);
}
}
};
Timer timer = new Timer();
long delay = 0;
long intevalPeriod = 10 * 1000;
timer.scheduleAtFixedRate(task, delay, intevalPeriod);
}
}
private void scanFile(File file) throws IOException {
if(file.isDirectory()) {
File[] filelist = file.listFiles();
for(File f : filelist) {
if(f.isDirectory()) {
scanFile(f);
}else {
loadCache(f);
}
}
}else {
loadCache(file);
}
}
private void loadCache(File file) throws IOException {
String fileName = file.getName();
if(PropertiesUtils.isPropertiesFile(fileName)) {
String key = file.getAbsolutePath().replace(configPath, "");
long value = file.lastModified();
Long date = map.get(key);
if(date == null) {
//如果为空则说明是新增的文件,也需要再次推送
pushProperties(file);
map.put(key, value);
}else {
if(date.longValue() != value) {//修改时间不等,则更新
pushProperties(file);
map.put(key, value);
}
}
}
}
private void pushProperties(File file) throws IOException {
String applicationName = getApplicationName(file);
if(applicationName == null) {
logger.info("获取不到application name,file: " + file.getAbsolutePath());
return;
}
//重新推送该文件
PropertiesUtils.loadFile(file);
//加载完成后,往jms推送消息
if(!PropertiesUtils.list.isEmpty()) {
for(PropertiesBean pb : PropertiesUtils.list) {
pb.setApplicationName(applicationName);
String json = JsonUtils.toJson(pb);
productor.sendMessage(JmsDestination.getDestination(destination, true), json);
logger.info("已推送properties:" + json);
}
PropertiesUtils.list.clear();
}
//productor.sendMessage(JmsDestination.getDestination(destination, true), file.getAbsolutePath());
}
private String getApplicationName(File file) {
File parentFile = file.getParentFile();
if(parentFile != null) {
String applicationName = null;
while(!parentFile.getAbsolutePath().equals(configPath)) {
applicationName = parentFile.getName();
parentFile = parentFile.getParentFile();
if(parentFile == null) {
return null;
}
}
return applicationName;
}
return null;
}
}
- 每个服务启动时加载文件
public class PropertiesUtils {
private static final Logger logger = LoggerFactory.getLogger(PropertiesUtils.class);
private static String ENV = EnvContants.DEV_ENV;
private static String CONFIG_PATH = null;
private static final String SUPPORT_ENV = ".dev.|.test.|.pro.";
private static final String SUFFIX = ".properties";
private static final String BASE_URL = PropertiesUtils.class.getResource("/").getPath();
// private static final String BASE_URL = ResourceUtils.getFile("classpath:config/").getPath();
private static Properties properties = new Properties();
private static final String CONFIG = "config:";
private static final String PACKAGE = "package:";
private static final String TEST_FILE_NAME = "test-classes";
private static final String MAIN_FILE_NAME = "classes";
public static List<PropertiesBean> list = new ArrayList<PropertiesBean>();
public static Map<Map<String, String>, Class<?>> fieldCache = new HashMap<Map<String, String>, Class<?>>();
//项目启动时初始化对应的配置信息
static {
String scanPackages = null;
try {
scanPackages = analyzeYml();
} catch (IOException e) {
logger.error("初始化yml异常", e);
}
if(scanPackages != null) {
for(String scanPackage : scanPackages.split(",")) {
Set<Class<?>> set = getClasses(scanPackage);
for(Class<?> cla : set) {
if(cla.getAnnotation(PropertiesClass.class) != null) {//获取PropertiesClass注解的上类
//获取该类上的所有字段,并且该字段上有PropertiesKey注解
Field[] fields = cla.getFields();
Map<String, String> map = new HashMap<String, String>();
for(Field field : fields) {
Annotation annotation = field.getAnnotation(PropertiesKey.class);
if(annotation != null) {
PropertiesKey propertiesKey = (PropertiesKey)annotation;
String key = propertiesKey.value();
map.put(field.getName(), key);
}
}
if(!map.isEmpty()) {
fieldCache.put(map, cla);
}
}
}
}
}else {
logger.warn("未获取扫描properties的包");
}
}
private static String analyzeYml() throws IOException {
URL u = PropertiesUtils.class.getResource("/");
if(u == null) {
return null;
}
String protocol = u.getProtocol();
logger.info("protocol: " + protocol);
if ("file".equals(protocol)) {
URL url = PropertiesUtils.class.getResource("/application.yml");
InputStreamReader isr = new InputStreamReader(url.openStream());
BufferedReader br = new BufferedReader(isr);
String str = null;
try {
while((str = br.readLine()) != null) {
if(str.trim().equals(CONFIG)) {
str = br.readLine();
while(str != null && str.startsWith(" ")) {
String result = analyzeConfig(str);
if(result != null) {
return result;
}
str = br.readLine();
}
break;
}
}
return null;
}finally {
if(br != null) {
br.close();
}
if(isr != null) {
isr.close();
}
}
}else {
URL url = PropertiesUtils.class.getClassLoader().getResource("BOOT-INF/classes/application.yml");
InputStreamReader isr = new InputStreamReader(url.openStream());
BufferedReader br = new BufferedReader(isr);
String str = null;
try {
while((str = br.readLine()) != null) {
if(str.trim().equals(CONFIG)) {
str = br.readLine();
while(str != null && str.startsWith(" ")) {
String result = analyzeConfig(str);
if(result != null) {
return result;
}
str = br.readLine();
}
break;
}
}
return null;
}finally {
if(br != null) {
br.close();
}
if(isr != null) {
isr.close();
}
}
}
}
private static String analyzeConfig(String str) {
if(str.contains(PACKAGE)) {
return str.trim().replace(PACKAGE, "").trim();
}
return null;
}
private static Set<Class<?>> getClasses(String pack) {
// 第一个class类的集合
Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
// 是否循环迭代
boolean recursive = true;
// 获取包的名字 并进行替换
String packageName = pack;
String packageDirName = packageName.replace('.', '/');
// 定义一个枚举的集合 并进行循环来处理这个目录下的things
Enumeration<URL> dirs;
try {
dirs = Thread.currentThread().getContextClassLoader().getResources(
packageDirName);
// 循环迭代下去
while (dirs.hasMoreElements()) {
// 获取下一个元素
URL url = dirs.nextElement();
// 得到协议的名称
String protocol = url.getProtocol();
// 如果是以文件的形式保存在服务器上
if ("file".equals(protocol)) {
// 获取包的物理路径
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
// 以文件的方式扫描整个包下的文件 并添加到集合中
findAndAddClassesInPackageByFile(packageName, filePath,
recursive, classes);
} else if ("jar".equals(protocol)) {
// 如果是jar包文件
// 定义一个JarFile
JarFile jar;
try {
// 获取jar
jar = ((JarURLConnection) url.openConnection())
.getJarFile();
// 从此jar包 得到一个枚举类
Enumeration<JarEntry> entries = jar.entries();
// 同样的进行循环迭代
while (entries.hasMoreElements()) {
// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
JarEntry entry = entries.nextElement();
String name = entry.getName();
// 如果是以/开头的
if (name.charAt(0) == '/') {
// 获取后面的字符串
name = name.substring(1);
}
// 如果前半部分和定义的包名相同
if (name.startsWith(packageDirName)) {
int idx = name.lastIndexOf('/');
// 如果以"/"结尾 是一个包
if (idx != -1) {
// 获取包名 把"/"替换成"."
packageName = name.substring(0, idx)
.replace('/', '.');
}
// 如果可以迭代下去 并且是一个包
if ((idx != -1) || recursive) {
// 如果是一个.class文件 而且不是目录
if (name.endsWith(".class")
&& !entry.isDirectory()) {
// 去掉后面的".class" 获取真正的类名
String className = name.substring(
packageName.length() + 1, name
.length() - 6);
try {
// 添加到classes
classes.add(Class
.forName(packageName + '.'
+ className));
} catch (ClassNotFoundException e) {
// log
// .error("添加用户自定义视图类错误 找不到此类的.class文件");
e.printStackTrace();
}
}
}
}
}
} catch (IOException e) {
// log.error("在扫描用户定义视图时从jar包获取文件出错");
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes;
}
/**
* 以文件的形式来获取包下的所有Class
*/
private static void findAndAddClassesInPackageByFile(String packageName,
String packagePath, final boolean recursive, Set<Class<?>> classes) {
// 获取此包的目录 建立一个File
File dir = new File(packagePath);
// 如果不存在或者 也不是目录就直接返回
if (!dir.exists() || !dir.isDirectory()) {
// log.warn("用户定义包名 " + packageName + " 下没有任何文件");
return;
}
// 如果存在 就获取包下的所有文件 包括目录
File[] dirfiles = dir.listFiles(new FileFilter() {
// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
public boolean accept(File file) {
return (recursive && file.isDirectory())
|| (file.getName().endsWith(".class"));
}
});
// 循环所有文件
for (File file : dirfiles) {
// 如果是目录 则继续扫描
if (file.isDirectory()) {
findAndAddClassesInPackageByFile(packageName + "."
+ file.getName(), file.getAbsolutePath(), recursive,
classes);
} else {
// 如果是java类文件 去掉后面的.class 只留下类名
String className = file.getName().substring(0,
file.getName().length() - 6);
try {
// 添加到集合中去
//classes.add(Class.forName(packageName + '.' + className));
//经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
} catch (ClassNotFoundException e) {
// log.error("添加用户自定义视图类错误 找不到此类的.class文件");
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws IOException {
String url = PropertiesUtils.class.getResource("/config").getPath();
File file = new File(url);
loadFiles(file);
}
/**
* 设置环境
*/
public static void setEnv(String env) {
PropertiesUtils.ENV = env;
}
/**
* 设置配置路径
*/
public static void setConfigPath(String path) {
PropertiesUtils.CONFIG_PATH = path;
}
/**
* 加载指定目录下的配置文件
*
*/
public static void loadFiles(File file) throws IOException {
logger.info("---------------loadFiles start------------------");
if(file.isDirectory()) {
logger.info("dic: " + file.getName() + ", path: " + file.getPath());
File[] filelist = file.listFiles();
for(File f : filelist) {
if(f.isDirectory()) {
loadFiles(f);
}else {
doProperties(f);
}
}
}else {
logger.info("file: " + file.getName() + ", path: " + file.getPath());
doProperties(file);
}
logger.info("---------------loadFiles end------------------");
}
/**
* 加载配置文件
*
*/
public static void loadFile(File file) throws IOException {
logger.info("---------------loadFile start------------------");
logger.info("file: " + file.getName() + ", path: " + file.getPath());
doProperties(file);
logger.info("---------------loadFile end------------------");
}
/**
* 判断是否是properties文件
*/
public static boolean isPropertiesFile(String fileName) {
int index = fileName.lastIndexOf(".");
if(index == -1) {
return false;
}
String fileSuffix = fileName.substring(index);
return SUFFIX.equals(fileSuffix);
}
/**
* 解析properties文件
*/
private static void doProperties(File file) throws IOException {
String fileName = file.getName();
if(isPropertiesFile(fileName)) {//只处理properties
String classpathFile = getRelativePath(file.getAbsolutePath());
//根据不同环境过滤掉
if(!isUseEnv(classpathFile)) {
return;
}
String configFileName = getConfigFileName(file);
init(classpathFile, configFileName);
}
}
/**
* 初始化properties文件
*/
private static void init(String classpathFile, String configFileName) {
InputStreamReader isr = null;
InputStream in = null;
try {
if(EnvContants.DEV_ENV.equals(PropertiesUtils.ENV)) {//本地环境
ClassLoader classLoader = Thread.currentThread()
.getContextClassLoader();
in = classLoader.getResourceAsStream(classpathFile);
}else {
in = new FileInputStream(classpathFile);
}
isr = new InputStreamReader(in, "UTF-8");
Properties props = new Properties();
props.load(isr);
PropertiesBean propertiesBean = new PropertiesBean();
propertiesBean.setEnv(PropertiesUtils.ENV);
propertiesBean.setName(configFileName);
propertiesBean.setProperties(props);
list.add(propertiesBean);
} catch (Exception e) {
logger.error("初始化properties文件异常", e);
} finally {
if (isr != null) {
try {
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 获取配置文件根路径文件名
*/
private static String getConfigFileName(File file) {
File parentFile = file.getParentFile();
if(parentFile == null) {
return null;
}
if(parentFile.getAbsolutePath().equals(PropertiesUtils.CONFIG_PATH)) {
return file.getName();
}else {
return getConfigFileName(parentFile);
}
}
/**
* 获取相对路径地址
*/
private static String getRelativePath(String path) {
if(!EnvContants.DEV_ENV.equals(PropertiesUtils.ENV)) {
return path;
}
String relativePath = path.replaceAll("\\\\", "/");
if(!relativePath.startsWith("/")) {
relativePath = "/" + relativePath;
}
String baseUrl = BASE_URL;
if(baseUrl.lastIndexOf("/" + PropertiesUtils.TEST_FILE_NAME + "/") != -1) {
baseUrl = baseUrl.replace("/" + PropertiesUtils.TEST_FILE_NAME + "/", "/" + PropertiesUtils.MAIN_FILE_NAME + "/");
}
relativePath = relativePath.substring(baseUrl.length());
return relativePath;
}
/**
* 匹配当前使用的环境
*/
private static boolean isUseEnv(String path) {
String p = path.substring(0, path.lastIndexOf(".") + 1);
p = p.substring(p.lastIndexOf("/") + 1);
String supportEnvs[] = SUPPORT_ENV.split("\\|");
boolean isSupportEnv = false;
for(String supportEnv : supportEnvs) {
//获取.properties之前的文件格式
if(p.lastIndexOf(supportEnv) != -1) {
isSupportEnv = true;
if(p.contains("." + ENV + ".")) {
return true;
}
}
}
if(!isSupportEnv) {
return true;
}
return false;
}
/**
* 获取值
*/
public static String getValue(String key) {
if(EnvContants.DEV_ENV.equals(PropertiesUtils.ENV) && properties.isEmpty()) {//本地环境
String url = PropertiesUtils.class.getResource("/config").getPath();
File file = new File(url);
try {
PropertiesUtils.loadFiles(file);
} catch (IOException e) {
logger.error("load properties fail. path=" + file.getPath(), e);
}
}
return String.valueOf(properties.get(key));
}
public static int getIntegerValue(String key) {
return Integer.parseInt(String.valueOf(properties.get(key)));
}
public static long getLongValue(String key) {
return Long.parseLong(String.valueOf(properties.get(key)));
}
public static double getDoubleValue(String key) {
return Double.parseDouble(String.valueOf(properties.get(key)));
}
public static float getFloatValue(String key) {
return Float.parseFloat(String.valueOf(properties.get(key)));
}
public static boolean getBooleanValue(String key) {
return Boolean.parseBoolean(String.valueOf(properties.get(key)));
}
public static void put(String key, String value) {
properties.put(key, value);
}
}
上面的代码比较长,分块来看
- 启动时调用静态代码块的代码,执行配置文件的解析,读取application.yml配置中的
config:
package: xxx #需要扫描的包
path: xxx #配置文件的物理目录
读到这个config后,会扫描package下面的包,多个包用都好隔开
只要发现这些包下面的class标有@PropertiesClass注解,那么将该类进行每个字段的扫描,知道发现成员属性上是否有@PropertiesKey注解
- 将标记有@PropertiesKey注解的属性存储到fieldCache缓存中
- 项目启动后会调用loadFiles方法进行反射赋值
@Service
public class ApplicationStartupEvent implements ApplicationListener<ApplicationPreparedEvent> {
private static Logger logger = LoggerFactory.getLogger(ApplicationStartupEvent.class);
@Value("${spring.application.name}")
private String applicationName;
@Value("${config.path}")
private String configPath;
@Autowired
private Environment env;
@Override
public void onApplicationEvent(ApplicationPreparedEvent event) {
//初始化加载配置
//根据name去搜索对应的properties存放目录,然后推给对应的服务
String currentEnv = env.getActiveProfiles()[0];
PropertiesUtils.setEnv(currentEnv);
PropertiesUtils.setConfigPath(configPath);
if(!EnvContants.DEV_ENV.equals(currentEnv)) {//本地环境不需要加载,过滤掉
if(StringUtils.isBlank(configPath)) {
logger.warn("no config path in application.yml");
return;
}
File file = new File(configPath + "/" + applicationName);
if(!file.exists()) {
logger.info("配置文件不存在," + file.getAbsolutePath());
return;
}
try {
PropertiesUtils.loadFiles(file);
} catch (Exception e) {
logger.error("load properties fail. path: " + configPath, e);
}
}else {
String url = PropertiesUtils.class.getResource("/config").getPath();
File file = new File(url);
try {
PropertiesUtils.loadFiles(file);
} catch (IOException e) {
logger.error("load properties fail. path=" + file.getPath(), e);
}
}
//加载完成后,修改
synchronized(ApplicationStartupEvent.class) {
if(!PropertiesUtils.list.isEmpty()) {
for(PropertiesBean propertiesBean : PropertiesUtils.list) {
Properties properties = propertiesBean.getProperties();
Set<Map.Entry<Object, Object>> set = properties.entrySet();
for(Map.Entry<Object, Object> entry : set) {
PropertiesUtils.put(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));
}
}
for(Entry<Map<String, String>, Class<?>> entry : PropertiesUtils.fieldCache.entrySet()) {
Class<?> cla = entry.getValue();
Field[] fields = cla.getFields();
Map<String, String> map = entry.getKey();
for(Field field : fields) {
String key = map.get(field.getName());
if(StringUtils.isNotBlank(key) && StringUtils.isNotBlank(PropertiesUtils.getValue(key))) {
//不同类型获取不同的类型的值
String typeName = field.getType().getSimpleName();
logger.info("type: " + typeName);
logger.info("key: " + key);
logger.info("value: " + PropertiesUtils.getValue(key));
if(typeName.equals("Integer") || typeName.equals("int")) {
int value = PropertiesUtils.getIntegerValue(key);
try {
field.setInt(null, value);
} catch (Exception e) {
logger.error("set new properties value error", e);
}
}else if(typeName.equals("Long") || typeName.equals("long")) {
long value = PropertiesUtils.getLongValue(key);
try {
field.setLong(null, value);
} catch (Exception e) {
logger.error("set new properties value error", e);
}
}else if(typeName.equals("Boolean") || typeName.equals("boolean")) {
boolean value = PropertiesUtils.getBooleanValue(key);
try {
field.setBoolean(null, value);
} catch (Exception e) {
logger.error("set new properties value error", e);
}
}else if(typeName.equals("Double") || typeName.equals("double")) {
double value = PropertiesUtils.getDoubleValue(key);
try {
field.setDouble(null, value);
} catch (Exception e) {
logger.error("set new properties value error", e);
}
}else if(typeName.equals("Float") || typeName.equals("float")) {
float value = PropertiesUtils.getFloatValue(key);
try {
field.setFloat(null, value);
} catch (Exception e) {
logger.error("set new properties value error", e);
}
}else {
String value = PropertiesUtils.getValue(key);
try {
field.set(null, value);
} catch (Exception e) {
logger.error("set new properties value error", e);
}
}
}
}
}
PropertiesUtils.list.clear();
}
}
}
}
- 监听文件变化,配置文件变化后立即加载最新的内容到对应的属性中
@Component
public class PropertiesConsumer {
private static final Logger logger = LoggerFactory.getLogger(PropertiesConsumer.class);
@Value("${spring.application.name}")
private String applicationName;
@JmsListener(destination="q.properties.notify", containerFactory="pubSubContainerFactory")
public void subscribe(String text) {
logger.info("接收到q.properties.notify的订阅消息,text=" + text);
synchronized(ApplicationStartupEvent.class) {
PropertiesBean propertiesBean = JsonUtils.fromJson(text, PropertiesBean.class);
Properties properties = propertiesBean.getProperties();
if(!applicationName.equals(propertiesBean.getApplicationName())) {
return;
}
Set<Map.Entry<Object, Object>> set = properties.entrySet();
for(Map.Entry<Object, Object> entry : set) {
PropertiesUtils.put(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));
}
for(Entry<Map<String, String>, Class<?>> entry : PropertiesUtils.fieldCache.entrySet()) {
Class<?> cla = entry.getValue();
Field[] fields = cla.getFields();
Map<String, String> map = entry.getKey();
for(Field field : fields) {
String key = map.get(field.getName());
if(StringUtils.isNotBlank(key)) {
//不同类型获取不同的类型的值
String typeName = field.getType().getSimpleName();
logger.info("key: " + key);
if(typeName.equals("Integer") || typeName.equals("int")) {
int value = PropertiesUtils.getIntegerValue(key);
logger.info("value: " + value);
try {
field.setInt(null, value);
} catch (Exception e) {
logger.error("set new properties value error", e);
}
}else if(typeName.equals("Long") || typeName.equals("long")) {
long value = PropertiesUtils.getLongValue(key);
logger.info("value: " + value);
try {
field.setLong(null, value);
} catch (Exception e) {
logger.error("set new properties value error", e);
}
}else if(typeName.equals("Boolean") || typeName.equals("boolean")) {
boolean value = PropertiesUtils.getBooleanValue(key);
logger.info("value: " + value);
try {
field.setBoolean(null, value);
} catch (Exception e) {
logger.error("set new properties value error", e);
}
}else if(typeName.equals("Double") || typeName.equals("double")) {
double value = PropertiesUtils.getDoubleValue(key);
logger.info("value: " + value);
try {
field.setDouble(null, value);
} catch (Exception e) {
logger.error("set new properties value error", e);
}
}else if(typeName.equals("Float") || typeName.equals("float")) {
float value = PropertiesUtils.getFloatValue(key);
logger.info("value: " + value);
try {
field.setFloat(null, value);
} catch (Exception e) {
logger.error("set new properties value error", e);
}
}else {
String value = PropertiesUtils.getValue(key);
logger.info("value: " + value);
try {
field.set(null, value);
} catch (Exception e) {
logger.error("set new properties value error", e);
}
}
}
}
}
}
}
}
- 使用
//原先方式
public class xxxConstants {
public static final String XXX = System.getProperty("xxx");
...
}
//现有方式
@PropertiesClass
public class xxxConstants {
@PropertiesKey("xxx")
public static String XXX;
...
}
携程的Apollo方案
https://github.com/ctripcorp/apollo/wiki/Quick-Start
后期的所有项目都会全部接入Apollo方案,实现更好的管理