工作中突发奇想,可否将配置常量中的数据写入配置文件,每次使用配置文件加载常量。
配置文件
const.properties
FTP_HOST_NAME = 192.168.2.90
FTP_PORT = 21
FFMPEG_EXE = /usr/local/Cellar/ffmpeg/4.1_1/bin/ffmpeg
FFPROBE_EXE = /usr/local/Cellar/ffmpeg/4.1_1/bin/ffprobe
存放常量的类
public class Const {
public static final String FTP_HOST_NAME = null;
public static final String FTP_PORT = null;
public static final String FFMPEG_EXE = null;
public static final String FFPROBE_EXE = null;
}
程序
package com.test.config;
import org.springframework.core.io.ClassPathResource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
/*
* @Description: 自动将配置文件中的数据载入静态类
*/
public class AutoProperties {
//当配置文件中的属性找不到对应的常量时,会空指针异常
public static void init() {
//需要加载的配置文件
List<String> constPaths = new ArrayList<>();
constPaths.add("classPath:config/const.properties");
//对应配置文件坐标加载的类
List<String> classPaths = new ArrayList<>();
classPaths.add("com.aiface.util.Const");
autoPropertieByList(constPaths,classPaths);
}
//根据两个对应的list创建给常量赋值
public static void autoPropertieByList(List<String> constPaths,List<String> classPaths){
for (int i = 0; i < constPaths.size(); i++) {
InputStream inputStream = null;
try {
String propertiePath = constPaths.get(i);
//判断是否是classpath目录下的配置文件
if (propertiePath.contains("classPath:")) {
propertiePath = propertiePath.replace("classPath:","");
ClassPathResource classPathResource = new ClassPathResource(propertiePath);
inputStream = classPathResource.getInputStream();
}else{
File file = new File(propertiePath);
inputStream = new FileInputStream(file);
}
autoPropertie(inputStream, classPaths.get(i));
} catch (Exception e) {
System.out.println("自动填充Conts属性失败");
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
//自动填充我的配置文件
public static void autoPropertie(InputStream inputStream, String classPath) throws Exception {
//获取配置文件中的所有属性
Properties pro = new Properties();
pro.load(inputStream);
Iterator<String> it = pro.stringPropertyNames().iterator();
while (it.hasNext()) {
String key = it.next();
String value = pro.getProperty(key);
modify(classPath, key, value);
}
}
//通过反射修改一个final修饰的类
public static void modify(String classPath, String fieldName, Object newFieldValue) throws Exception {
//通过路径获取类文件
Class<?> c1 = Class.forName(classPath);
Field field = c1.getDeclaredField(fieldName);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true); //Field 的 modifiers 是私有的
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(c1, newFieldValue);
}
}
需要加载的配置文件和需要填充的常量类使用下标一一对应。
可以填充多个配置文件和存放常量的类
Springboot使用
在项目启动前填充存放常量的类。
@SpringBootApplication
@EnableDiscoveryClient
@EnableAsync //开启异步调用
public class AifaceWebApplication {
public static void main(String[] args) {
AutoProperties.init();
SpringApplication.run(AifaceWebApplication.class, args);
}
}
普通web项目
在监听器中配置一下(具体省略。。。。。)。
途中遇到的问题
Spring boot 读取resource下的properties文件。
Spring boot 在打包后变成了一个jar包,我们无法通过io流的方式读取配置文件了。
public static void getResoure(String resoure) throws IOException {
//resoure 不带classpath前缀哦
ClassPathResource classPathResource = new ClassPathResource(resoure);
InputStream inputStream = classPathResource.getInputStream();
Properties pro = new Properties();
pro.load(inputStream);
Iterator<String> it = pro.stringPropertyNames().iterator();
while (it.hasNext()) {
//得到key 和value的值
String key = it.next();
String value = pro.getProperty(key);
}
}
通过反射修改一个常量
/*
* @Description:通过反射修改一个常量
* @params classPath 类路径 如 com.abc.test.java
* @params fieldName 常量的名字
* @params newFieldValue 赋予的值
* @return void
* @date 2019/3/6 6:11 PM
*/
public static void modify(String classPath, String fieldName, Object newFieldValue) throws Exception {
//通过路径获取类文件
Class<?> c1 = Class.forName(classPath);
Field field = c1.getDeclaredField(fieldName);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true); //Field 的 modifiers 是私有的
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(c1, newFieldValue);
}