java项目 配置文件_细数Java项目中用过的配置文件(properties篇)
灵魂拷问:在不重启服务的前提下,如何让配置修改生效的呢?有什么奇技淫巧吗?
灵魂拷问:在 Java 项目中,总能看到以 .properties 为后缀的文件踪影,这类配置文件是怎么加载的呢?
项目研发过程中,总会遇到一些经常改变的参数,比如要连接的数据库的连接地址、名称、用户名、密码;再比如访问三方服务的 URL 等等。考虑到程序的通用性,这些参数往往不能直接写死在程序里,通常借助配置文件来优雅处理。
在 Java 项目中,properties 文件当属使用较简单一类,不过虽然简单,还是要好好说说项目中都是怎么使用的,尝试通过源码解读,让你真正懂它,并带你深刻体会 Java 中重载的意义。
1. 虽说简单,格式还是要看一看。
相比上次谈及的 ini 配置文件,properties 文件格式没有 Section (节)的概念,反而是简单了不少。
上图是一个 jdbc 连接所需要的配置,其中以 # 开始的每一行是注释信息,而以等号分割的每行配置,就是常说的键-值对,等号左边的为 key(代码中的变量),等号右边的为 value(是依据实际场景而配置的值)。
2. 虽说简单,Java 源码还是去要看看。
在 Java 中提供了 java.util.Properties 类,主要用于对配置文件的读写操作。
一图掌握血缘关系,很显然 Properties 继承自 Hashtable,归根结底是个 Map,而 Properties 最特殊的地方,就是它的键和值都是字符串类型。
从全局了解梗概,然后走进 JDK 源码,按照思路,步步去深入。
首先,要看看写好的配置文件是怎么加载的?
源码很清晰,提供字符流 Reader、字节流 InputStream两种方式加载配置文件(方法重载的目的:让使用者更方便),再深入去看最终会调用 Hashtable 的 put(key, value) 来设置键值对,最终完成配置文件中的加载。
然后,要看看怎么根据 key 获得对应的 value(放进去了,还要考虑拿出来)?
源码很清晰,通过参数 key 获得对应的 value,考虑到使用者的方便,对 getProperty 方法进行了重载,其中标注 2 的方法,当根据 key 获得值是 null 时,会返回一个调用方法时传入的默认值(很多场景下,确实很有用)。
知道了怎么加载配置文件,知道了怎么获取 key 对应的值,按照常理说,项目中已经够用了,但是有些时候项目启动后,还真需要再额外设置一下参数的值,不过没关系,因为 Java 已经想到了这一点,对外提供了 setProperty 的方法,让额外设置参数成为可能。
若能在项目研发中,熟练使用上面提到的这些 API,已经足矣。既然打开了源码,索性把杂七杂八的都提提,说不定某些 API 也能解决你碰到的其它场景的问题呢。
Properties 类不仅提供了 load 进行加载配置,而且还提供了把键值对写到文件中的能力。如上面源码所示,考虑到使用者的方便,对 store 方法进行重载,提供了面向字节流 OutputStream、字符流 Writer 两种方式的 store。
如上面源码所示,Properties 除了提供对常规配置文件读写能力支撑,对 xml 配置文件加载、写入也提供了支撑。
如上图源码所示,Properties 类提供了重载的 list 方法,为了方便调试,可以把键值对列表给整齐的打印出来。
3. 虽说简单,不能赋予实践一切都是扯淡。
场景一:在 APM 性能监控时,获取 Java 应用画像信息常用 API。
import java.util.Properties;
/**
* @author 一猿小讲
*/
public class JVMDetails {
public static void main(String[] args) {
// 获取系统信息(JDK信息、Java虚拟机信息、Java提供商信息、当前计算机用户信息)
Properties properties = System.getProperties();
// 把系统信息打印一下
properties.list(System.out);
}
}
程序跑起来,部分输出截图示意如下。
场景二:业务开发中,让配置替代硬编码,并考虑配置更新时,程序能够读到最新的值。
import java.io.*;
import java.util.Hashtable;
import java.util.Properties;
/**
* 配置文件工具类
* 1. 支持加载 .properties文件、.ini文件
* 2. 支持配置文件更新
* @author 一猿小讲
*/
public class PropertiesUtil {
// private static final Log4j LOG = .....;
private static Hashtable propCache = new Hashtable();
public static String getString(String propFile, String key) {
return getString(propFile, key, null);
}
public static String getString(String propFile, String key, String defaultValue) {
if ((!propFile.endsWith(".properties")) && (!propFile.endsWith(".ini"))) {
propFile = propFile + ".properties";
}
PropCache prop = propCache.get(propFile);
if (prop == null) {
try {
prop = new PropCache(propFile);
} catch (IOException e) {
// LOG.warn(e);
System.out.println(String.format("读取 %s 出现异常%s", propFile,e));
return defaultValue;
}
propCache.put(propFile, prop);
}
String value = prop.getProperty(key, defaultValue);
if (value != null) {
value = value.trim();
}
return value;
}
public static void setString(String propFile, String key, String value)
throws IOException {
if ((!propFile.endsWith(".properties")) && (!propFile.endsWith(".ini"))) {
propFile = propFile + ".properties";
}
File file = new File(propFile);
Properties prop = new Properties();
try {
FileInputStream fis = new FileInputStream(file);
prop.load(fis);
fis.close();
} catch (FileNotFoundException e) {
// LOG.warn(e);
System.out.println(String.format("文件 %s 不存在", propFile));
}
FileOutputStream fos = new FileOutputStream(file);
prop.put(key, value);
prop.store(fos, null);
fos.close();
PropCache localPropCache = propCache.get(propFile);
if (localPropCache != null) {
localPropCache.reload();
}
}
private static class PropCache {
private String fileName;
private long lastLoad;
private Properties prop;
public PropCache(String propFileName) throws IOException {
File file = new File(propFileName);
FileInputStream fis = new FileInputStream(file);
this.prop = new Properties();
this.prop.load(fis);
fis.close();
this.fileName = file.getAbsolutePath();
this.lastLoad = file.lastModified();
}
public String getProperty(String key, String defaultValue) {
File file = new File(this.fileName);
if (this.lastLoad < file.lastModified()) {
reload();
}
return this.prop.getProperty(key, defaultValue);
}
public void reload() {
File file = new File(this.fileName);
try {
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(file);
prop.load(fis);
fis.close();
this.prop.clear();
this.prop.putAll(prop);
this.lastLoad = file.lastModified();
} catch (IOException e) {
// PropertiesUtil.LOG.warn(e);
System.out.println(String.format("文件 %s 重新加载出现异常%s", this.fileName, e));
}
// PropertiesUtil.LOG.all(new Object[]{this.fileName, " reloaded."});
System.out.println(String.format("文件 %s 重新加载完毕", this.fileName));
}
}
}
借助开篇提到的 jdbc 配置文件,进行验证。尝试获取数据库类型,默认配置为 db2,中途修改参数的值为 mysql,看看效果如何?
/**
* 测试类
* @author 一猿小讲
*/
public class M {
public static void main(String[] args) {
while(true) {
System.out.println(PropertiesUtil.getString("db", "jdbc.type"));
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
}
}
}
程序跑起来,效果还是让人很满意。
4. 虽说简单,洋洋洒洒分享一大篇。
有关配置文件的分享网上有很多,而我们的分享却显得不太一样。
我们的初衷是:结合实际项目及源码,说说这些年用过的那些有关配置的奇技淫巧,帮你提高研发能力(那怕是提高一丢丢,就算成功)。
它山之石可以攻玉,相信会对你有所帮助。
为了能够帮你提高研发能力(那怕是提高一丢丢呢),后续将继续结合实际项目,看看用到的其它形式的配置文件,敬请期待。
java项目 配置文件_细数Java项目中用过的配置文件(properties篇)相关推荐
- c读取ini配置文件_细数Java项目中用过的配置文件(ini 篇)
Java 菜鸟,会把可变的配置信息写死在代码里:Java 老鸟,会把可变的配置信息提取到配置文件中.坊间流传这么一句非科学的衡量标准,来评判程序员的级别. 那么,项目中的配置信息,你平时都是怎样来实现 ...
- java 短路判断_细数Java最坑爹的10大功能点
作者:践行精神自由 原文:https://www.sohu.com/a/357927861_115128 作为一门面向对象的编程语言,Java凭借其简单易用.功能强大的特点受到了广大编程爱好者的青睐, ...
- 不允许使用java方式启动_细品 Java 中启动线程的正确和错误方式
细品 Java 中启动线程的正确和错误方式 前文回顾详细分析 Java 中实现多线程的方法有几种?(从本质上出发) start 方法和 run 方法的比较 代码演示:/** * * start() 和 ...
- 视频教程-大型Java项目视频教程_王勇老师DRP项目教程完整版292集-Java
大型Java项目视频教程_王勇老师DRP项目教程完整版292集 动力节点王勇老师,CCTV<影响力对话>栏目特约嘉宾,Java培训知名讲师,中国Java培训领军人物,北京动力节点创始人,董 ...
- php反序列化java.long_细数java中Long与Integer比较容易犯的错误总结
今天使用findbugs扫描项目后发现很多高危漏洞,其中非常常见的一个是比较两个Long或Integer时直接使用的==来比较. 其实这样是错误的. 因为Long与Ineger都是包装类型,是对象. ...
- 《八股文》细数Java线程、并发、锁,温故而知新
<八股文>细数Java线程.并发.锁,温故而知新 基础 1. 并行.并发有什么区别? 2. 说说什么是进程和线程? 3. 说说线程有几种创建方式? 4. 为什么调用start()方法时会执 ...
- yaml for java_细数Java项目中用过的配置文件(YAML篇)
灵魂拷问:YAML,在项目中用过没?它与 properties 文件啥区别? 目前 SpringBoot.SpringCloud.Docker 等各大项目.各大组件,在使用过程中几乎都能看到 YAML ...
- java ee论文_基于JavaEE的项目管理系统毕业论文.doc
基于JavaEE的项目管理系统毕业论文 基于JavaEE的项目管理系统的设计与实现 摘 要 企业项目管理系统是为了使企业项目能够按照预定的成本.进度.质量顺利完成,而对人员.产品.过程和项目进行分析和 ...
- jit java 怎么配置_新的Java JIT编译器Graal简介
在本教程中,我们将深入研究名为Graal的新Java实时(JIT)编译器. 让我们首先解释JIT编译器的作用. 当我们编译Java程序时(例如,使用 javac命令),我们最终将源代码编译成代码的二 ...
最新文章
- WMI技术介绍和应用——查询系统信息
- JAVA实现矩形覆盖问题(《剑指offer》)
- 2.Java异常学习
- 深入Garbage First垃圾收集器(三)G1中的垃圾收集
- altium designer2020中文版
- spring cloud的eureka.client.service-url.defaultZone配置eureka集群的写法
- python数码时钟代码_python时钟的实现
- Spark学习之RDD的概念
- UWP 手绘视频创作工具技术分享系列 - 位图的绘制
- 远程连接linux的mysql_【Linux开启mysql远程连接的设置步骤】 mysql开启远程连接
- intllij idea 快捷键 Mac
- raid5用户mbr还是gpt_系统硬盘gpt转换的操作方法
- 为什么不使用Go语言呢?
- 计算经纬度、距离、方位角
- 淘宝返利是怎么回事?是真的还是假的?
- java ico_Java 读写 ICO 图像
- 讯为4412蜂鸣器驱动实现
- 解决git中upstream丢失问题Your branch is based on 'origin/xxxx', but the upstream is gone.
- 如何快速将手写数据录入 Excel
- 计算机台式机硬盘,台式电脑硬盘和笔记本硬盘有什么区别【详解】
热门文章
- 如何对SAP Spartacus支持路由的Component进行单元测试
- SAP ABAP里存在Java List这种集合工具类么?CL_OBJECT_COLLECTION了解一下
- function implemented in Scala - compiled java code - some closure example
- when is odata request sent for Live report in SAP CRM
- how does SAP ui5 know the phone, tablet type, os type
- regular expression in SAP jam integration
- why COMM_PRFREEATTR could not appear in F4 help
- React的source code init时会自动检测Chrome dev tool的react extension装了没
- Employee Assign Organization unit
- 使用代码创建SAP Sales area