当前位置: 移动技术网 > IT编程>开发语言>Java > 细数Java项目中用过的配置文件(properties篇)

细数Java项目中用过的配置文件(properties篇)

2020年04月12日  | 移动技术网IT编程  | 我要评论

昆山社会保障网,雨城论坛,seo赚钱培训

灵魂拷问:在不重启服务的前提下,如何让配置修改生效的呢?有什么奇技淫巧吗?

灵魂拷问:在 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<string, propcache> propcache = new hashtable<string, propcache>();

    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. 虽说简单,洋洋洒洒分享一大篇。

有关配置文件的分享网上有很多,而我们的分享却显得不太一样。

我们的初衷是:结合实际项目及源码,说说这些年用过的那些有关配置的奇技淫巧,帮你提高研发能力(那怕是提高一丢丢,就算成功)。

它山之石可以攻玉,相信会对你有所帮助。

为了能够帮你提高研发能力(那怕是提高一丢丢呢),后续将继续结合实际项目,看看用到的其它形式的配置文件,敬请期待。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网