Above, we modeled the elegant practice of parsing configuration information from Spring source code, covering the vast majority of everyday development situations. However, sometimes there is not enough flexibility, such as the requirement to configure consistent key prefixes. By implementing EnvironmentAware interfaces or injecting beans into the Environment, using getProperty() can solve the problem of setting values when configuration keys are discrete and not associated. However, it is always necessary to implement interfaces or inject beans, and it is difficult to break free from Spring’s shackles. Can’t help but dance in chains?

IO way

Back to the language level, Java itself has IO support. Can’t we just read the file by IO and parse it into a key-value data structure. Read into a stream and then parse, sensory inevitably feel very troublesome, solve the problem at the same time bring more new problems, contrary to the original intention. In fact, the JDK provides a convenient Api for everyone to use. In addition to loading class information, the ClassLoader is also useful for reading properties files. GetResourceAsStream () supports converting a configuration file to an InputStream. The JDK also provides easy and friendly support for parsing. Load () in the java.util.properties class allows the input stream to be parsed into key-value pairs. Right place, right time.

The parsing process

The specified stream remains open after this method returns

It is important to note that the JDK does what it says about Load () : When this method returns, the specified stream remains open. This means that we must manually close the stream to avoid memory waste.

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(a) {}

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

    public Properties getProperties(a) {
        return properties;
    }

    private enum Loader {
        INSTANCE;

        private JavaLoadResources loader;

        private Loader(a) {
            loader = newJavaLoadResources(); }}}Copy the code

But at the end of the day, the code still doesn’t call the stream close(), and why is the try-catch structure different? This is using the try-with-Resources syntax sugar provided after Java 1.7. The Java class library contains many resources that must be manually closed by calling close(). InputStream, OutputStream. Customers often neglect to shut down resources, with predictable performance results. In his book Effective Java, Bloch, the father of the Java collections framework, writes:

The try-with-resources versions are leaner and more readable than the original, and they provide better diagnostics.

A catch clause can be added to a try-with-resources statement, just as ina regular try-finally statement. This allows you to handle exceptions without contaminating code in another layer of nesting.

Try-with-resources automatically closes the resource after executing the try block. The prerequisite is that you must implement the Closeable interface. Ta is the best way to ensure that resources are shut down correctly.

In addition, utility classes are generally designed as singletons. It is recommended to use an enumerated class that declares a single element. This is the approach Bloch most approves of. From Effective Java:

This approach is similar to the public properties approach, but is more concise, provides a free serialization mechanism, and provides a robust guarantee against multiple instantiations, even in the case of complex serialization or reflection attacks. This approach may feel a little unnatural, but enumerating classes for a single element is often the best way to implement a singleton.

Note that this approach cannot be used if a singleton must inherit from a parent class other than an Enum (although an Enum can be declared to implement the interface).

The test code

Iterate over the output and simply verify it

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); }}Copy the code

Properties configuration file information is as follows:

As expected, this makes it easier and more flexible to get configuration information without relying on Spring.