Java IO获取配置信息的正确姿式

上文,咱们效仿Spring源码,完成了解析配置信息的优雅实践,能够覆盖平常开发中绝大多数的情形。可是有时候仍是不够灵活,好比要求配置键前缀一致。
经过实现EnvironmentAware接口,或者注入Environment的bean,使用getProperty()虽然能够解决配置键比较离散、没有关联情形下的取值问题。但总要实现接口或者注入bean,不能为所欲为,难以挣脱Spring的桎梏。难免意难平,难道就只能带着镣铐起舞吗?java

IO的方式

回归语言的层面上来,Java自己具有IO强大的支持。咱们就不能经过IO的方式读取文件,而后解析成键值对的数据结构吗。
读取成流再进行解析,感官上不免以为十分麻烦,解决问题的同时带来更多新的问题,有悖初衷。其实JDK提供了便捷的Api供你们使用。
ClassLoader除了能够加载类信息以外,读取properties文件也是一把好手。getResourceAsStream()支持将配置文件转化成InputStream
同时解析过程JDK提供的支持也足够轻松友好,java.util.Properties类中的load()整好可使得输入流解析成为键值对。如此这般,可谓天时地利人和。spring

解析过程

The specified stream remains open after this method returns数据结构

这里必须注意,JDK对load()有如上说明: 此方法返回后,指定的流保持打开状态。也就是说咱们必须手动关闭流,以避免形成内存浪费。框架

package com.spring.load_properties;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/** * @Author: Raphael */
public class JavaLoadResources {

    private static final Properties properties;

    static {
        properties = new Properties();
        try (
            InputStream in = ClassLoader.getSystemClassLoader()
                        .getResourceAsStream("value.properties"))
        {
            properties.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private JavaLoadResources() {}

    public static JavaLoadResources getIntance() {
        return Loader.INSTANCE.loader;
    }

    public Properties getProperties() {
        return properties;
    }

    private enum Loader {
        INSTANCE;

        private JavaLoadResources loader;

        private Loader() {
            loader = new JavaLoadResources();
        }
    }

}
复制代码

可是看到最后,代码中依然没有调用流的close(),并且为何try-catch的结构也有差别?其实这里是使用了Java 1.7以后提供的try-with-resources语法糖。Java类库中包含许多必须经过调用close()手动关闭的资源。好比InputStreamOutputStream。客户常常忽视关闭资源,其性能结果可想而知。
Java集合框架之父布洛赫在其著做《Effective-Java》中如此论述:工具

try-with-resources版本比原始版本更精简,更好的可读性,并且它们提供了更好的诊断。 能够在 try-with-resources 语句中添加 catch 子句,就像在常规的 try-finally 语句中同样。这容许你处理异常,而 不会在另外一层嵌套中污染代码。post

try-with-resources会在执行完try代码块后自动关闭资源。前提是你必须实现了Closeable接口。ta是保证资源正确关闭的最佳方式。性能

此外工具类通常设计为单例模式。 这里推荐你们使用声明单一元素的枚举类的方式实现。这也是布洛赫最为赞同的实现方式。《Effective-Java》中如此论述:

这种方式相似于公共属性方法,但更简洁,提供了免费的序列化机制,并提供了针对多个实例化的坚固保证,即便是在复杂的序列化或反射攻击的状况下。这种方法可能感受有点不天然,可是单一元素枚举类一般是实现单例的最佳方式。
注意,若是单例必须继承 Enum 之外的父类(尽管能够声明一个Enum来实现接口),那么就不能使用这种方法。测试

测试代码

遍历输出,简单的验证一下便可this

package com.spring.load_properties;

import java.util.Properties;
import java.util.function.BiConsumer;

public class GetProperties {

    /** * @Author: Raphael */
    public static void main(String[] args) {
        JavaLoadResources intance = JavaLoadResources.getIntance();
        Properties properties = intance.getProperties();
        BiConsumer console = (k, v) -> {
            System.out.print(k + ": ");
            System.out.println(v);
        };
        properties.forEach(console);
    }

}

复制代码

value.properties配置文件信息以下:

彻底符合预期,这样一来咱们即可以在不依赖Spring的状况下更加便捷、灵活的获取配置信息。
相关文章
相关标签/搜索