ホームページ  >  記事  >  Java  >  プロパティファイルを読み取る6つの方法、集めるのがおすすめ!

プロパティファイルを読み取る6つの方法、集めるのがおすすめ!

Java后端技术全栈
Java后端技术全栈転載
2023-08-15 16:03:24528ブラウズ

手書きの分散構成センターは段階的に進行中です。

最近では、開発には基本的に Spring Boot が使用されており、プロジェクト内に application.properties 構成ファイルが存在することは誰もが知っています (一部は application も使用します) .yaml、とにかく、構成情報の一部を保存するために使用されます)、通常は、データベース接続情報、サードパーティのインターフェイス情報 (キー、ユーザー名、パスワード、アドレスなど)、接続プール、Redis 構成情報、さまざまなサードパーティコンポーネント構成情報など。

単一サービス、または一部の小規模な分散アーキテクチャでも、プロジェクト構成は application.properties 構成ファイルに依存します (一部のプロジェクトには環境の区別がある場合があります。例: application -dev.propertiesapplication-pro.properties など)。しかし、ビジネスが発展し、アーキテクチャがアップグレードされ続けるにつれて、各サービスに関係するサービス データと構成情報がますます増加し、リアルタイムでの独立した構成など、構成管理の要件もますます高くなります。情報、性別など

同時に、マイクロサービス アーキテクチャでは、構成管理、グレースケール パブリッシング、動的な電流制限、動的なダウングレード、および構成コンテンツのセキュリティやアクセス許可など、さまざまな環境でのその他の要件が関係する場合があります。構成やメンテナンスの方法がニーズを満たすのは困難です。

分散構成センターはこのような環境で誕生しました。

この記事では、まず Java でプロパティ設定ファイルを読み取るためのメソッドが何であるかを理解します。

#Java がプロパティ設定ファイルを読み取る 6 つの方法

要件の背景 #要件は、プロジェクトに次のような

jdbc.properties

構成ファイルがあることです。 <pre class="brush:php;toolbar:false;">jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=mysql://localhost:3306/database?useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=Asia/Shanghai jdbc.username=root jdbc.password=123456</pre> ここで、上記の内容を取得したいとします。 Java コード内の構成ファイル。

最初の方法最初に使用する方法:

this.getClass().getResourceAsStream()

Propertiesコード実装:

/**
* @author tianwc  公众号:java后端技术全栈、面试专栏
* @version 1.0.0
* @date 2023年05月27日 09:13
* 在线刷题1200+,100+篇干货文章:<a href="http://woaijava.cc/">博客地址</a>
*/
public void readProperties1() throws IOException {
    //不加/会从当前包进行寻找,加上/会从src开始找
    InputStream inputStream = this.getClass().getResourceAsStream("/jdbc.properties");
    Properties properties=new Properties();
    properties.load(inputStream);
    System.out.println("jdbc.driver="+properties.getProperty("jdbc.driver"));
    System.out.println("jdbc.url="+properties.getProperty("jdbc.url"));
    System.out.println("jdbc.username="+properties.getProperty("jdbc.username"));
    System.out.println("jdbc.password="+properties.getProperty("jdbc.password"));
}

上記のコードについて話しましょう:

this.getClass().getResourceAsStream ()

具体的なファイルとコードの場所は、コードは
src/main/java

ディレクトリにあり、リソース ファイルです。 src/main/resources/ ディレクトリにあります。 は現在のクラスのディレクトリから検索されます。このファイルがクラスと同じディレクトリにない場合は見つかりません。

は、コンパイルされたクラス ディレクトリ全体から見つかります。また、Maven は、リソース ファイルをクラス フォルダーにパッケージ化して、見つけられるようにします。

ClassLoader はクラス フォルダー全体から見つかるため、/

#プロパティを追加する必要はありません。

プロパティ: java.util.Properties、このクラスは主に Java 構成ファイルを読み取るために使用されます。さまざまなプログラミング言語には独自のサポート構成があります。構成ファイル内の多くの変数は頻繁に変更されます。ユーザー構成を容易にするために、ユーザーはプログラム自体を終了せずに関連する変数設定を変更できます。 Java と同様に、その構成ファイルは多くの場合 .properties ファイルであり、キーと値のペアの形式でパラメーターを構成します。

クラス関係図:

プロパティファイルを読み取る6つの方法、集めるのがおすすめ!

上記のクラス図から、Properties クラスが Hashtable を継承していることがわかります。誰もが知っていますHashtable は、プロパティ ファイルの内容に対応するキーと値のデータ構造クラスであり、これもキーと値の形式です。

プロパティの共通メソッド

getProperty(String key) : このプロパティ リストで指定されたキーを持つプロパティを検索します。 。このプロパティ リストにキーが見つからない場合は、デフォルトのプロパティ リストとそのデフォルト値が (再帰的に) チェックされます。プロパティが見つからない場合、メソッドはデフォルト値パラメータを返します。

list(PrintStream out) このプロパティ リストを指定された出力ストリームに出力します。このメソッドはデバッグに役立ちます。

load(InputStream inStream) : 入力バイト ストリームから属性リスト (キーと要素のペア) を読み取ります。入力ストリームは、ロード (リーダー) で指定された単純な行指向形式であり、ISO 8859-1 文字エンコーディング、つまり各バイトが Latin1 文字であることを前提としています。 Latin1 にない文字と特定の特殊文字は、Unicode エスケープを使用してキーと要素で表されます。このメソッドが戻った後も、指定されたストリームは開いたままになります。

setProperty(String key, String value): Hashtable メソッド put を呼び出します。彼は、基本クラスの put メソッドを呼び出して、キーと値のペアを設定します。

store(OutputStream out, String comments) : このプロパティ テーブルのプロパティ (キーと要素のペア) のリスト。load(InputStream を使用してプロパティ テーブルにロードするのに適した形式になっています) ) メソッド 出力ストリームに書き込みます。この Properties メソッドは、この Properties テーブルのデフォルト テーブルにプロパティ (存在する場合) を書き込みません。

storeToXML(OutputStream os, String comment, String encoding) : 指定されたエンコーディングを使用して、このテーブルに含まれるすべての属性を表す XML ドキュメントを出力します。

clear() : このハッシュ テーブルをクリアして、キーが含まれないようにします。

stringPropertyNames() : 同じ名前のキーが見つからなかった場合、このプロパティ リスト内のキーのセットを返します。キーとそれに対応する値は文字列です。メインのプロパティ リストに、デフォルトのプロパティ リストの異なるキーを含めます。キーまたはキーの型が String でないプロパティは省略されます。

properties.load(inputStream)
public synchronized void load(InputStream inStream) throws IOException {
        load0(new LineReader(inStream));
    }

    private void load0 (LineReader lr) throws IOException {
        char[] convtBuf = new char[1024];
        int limit;
        int keyLen;
        int valueStart;
        char c;
        boolean hasSep;
        boolean precedingBackslash;
        //逐行读取
        while ((limit = lr.readLine()) >= 0) {
            c = 0;
            keyLen = 0;
            valueStart = limit;
            hasSep = false;

            //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
            precedingBackslash = false;
            while (keyLen < limit) {
                c = lr.lineBuf[keyLen];
                //need check if escaped.
                if ((c == &#39;=&#39; ||  c == &#39;:&#39;) && !precedingBackslash) {
                    valueStart = keyLen + 1;
                    hasSep = true;
                    break;
                } else if ((c == &#39; &#39; || c == &#39;\t&#39; ||  c == &#39;\f&#39;) && !precedingBackslash) {
                    valueStart = keyLen + 1;
                    break;
                }
                if (c == &#39;\\&#39;) {
                    precedingBackslash = !precedingBackslash;
                } else {
                    precedingBackslash = false;
                }
                keyLen++;
            }
            while (valueStart < limit) {
                c = lr.lineBuf[valueStart];
                if (c != &#39; &#39; && c != &#39;\t&#39; &&  c != &#39;\f&#39;) {
                    if (!hasSep && (c == &#39;=&#39; ||  c == &#39;:&#39;)) {
                        hasSep = true;
                    } else {
                        break;
                    }
                }
                valueStart++;
            }
            //前面一堆代码就是做校验和解析
            //下面两个是做转换
            String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
            String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
            
            put(key, value);
        }
    }

最后调用put(key, value);这个put方法就是Hashtable中的put方法。这里可以这么理解:将我们的配置项保存到Hashtable中。

getProperty(String key)
public String getProperty(String key) {
    Object oval = super.get(key);
    String sval = (oval instanceof String) ? (String)oval : null;
    return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
}

super.get(key);就是调用Hashtable中的get()方法,也就是此时返回value,同时这就对应返回了properties文件中key对应的value。

第二种方式

第二种方式,我们通过当前类的加载器进行读取this.getClass().getClassLoader().getResourceAsStream()获取InputStream。

代码实现:

/**
* @author tianwc  公众号:java后端技术全栈、面试专栏
* @version 1.0.0
* @date 2023年05月27日 09:13
* 博客地址:<a href="http://woaijava.cc/">在线刷题1200+,100+篇干货文章</a>
*/
public void readProperties2() throws IOException {
    //不加/,若加了会为null
    InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("jdbc.properties");
    //如果放在config目录下
    //InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("config/jdbc.properties");
    Properties properties=new Properties();
    properties.load(inputStream);
    System.out.println("jdbc.driver="+properties.getProperty("jdbc.driver"));
    System.out.println("jdbc.url="+properties.getProperty("jdbc.url"));
    System.out.println("jdbc.username="+properties.getProperty("jdbc.username"));
    System.out.println("jdbc.password="+properties.getProperty("jdbc.password"));
}

第一看怎么觉得和第一种方式很像,下面来说说两个的区别。

  • this.getClass.getResourceAsStream() 現在のクラスの場所から開始して構成ファイルの場所を検索します。 jdbc.properties を見つけるには、/start from classpath を追加し、
  • #this.getClass( ).getClassLoader().getResourceAsStream() デフォルトでは、検索は classpath パスから開始され、/ を追加すると null ポインター例外が報告されます

コードの残りの部分は最初の方法と同じなので、ここでは詳しく説明しません。

3 番目の方法

次に、ClassLoader クラスの静的メソッドを使用します。 getSystemResourceAsStream()

/**
* @author tianwc  公众号:java后端技术全栈、面试专栏
* @version 1.0.0
* @date 2023年05月27日 09:13
* 博客地址:<a href="http://woaijava.cc/">在线刷题1200+,100+篇干货文章</a>
*/
public void readProperties3() throws IOException {
    //如果存放到config目录下
    //InputStream inputStream = ClassLoader.getSystemResourceAsStream("config/jdbc.properties");
    InputStream inputStream = ClassLoader.getSystemResourceAsStream("jdbc.properties");
    Properties properties=new Properties();
    properties.load(inputStream);
    System.out.println("jdbc.driver="+properties.getProperty("jdbc.driver"));
    System.out.println("jdbc.url="+properties.getProperty("jdbc.url"));
    System.out.println("jdbc.username="+properties.getProperty("jdbc.username"));
    System.out.println("jdbc.password="+properties.getProperty("jdbc.password"));
}

ClassLoader中的getSystemResourceAsStream()方法,它用于获取资源作为参数并将资源转换为InputStream。例如,我们可以使用该方法获取网站的静态资源并将其转换为InputStream

说白了就是获取InputStream的方式不同罢了,最终还是交给Properties去解析jdbc.properties文件内容。

第四种方式

我们在实际开发中,基本上都是离不开Spring了,所以,接下来我们使用Spring中的 ClassPathResource读取配置文件。

代码实现:

/**
* @author tianwc  公众号:java后端技术全栈、面试专栏
* @version 1.0.0
* @date 2023年05月27日 09:13
* 博客地址:<a href="http://woaijava.cc/">博客地址</a>
*/
public void readProperties4() throws IOException {
    ClassPathResource resource = new ClassPathResource("jdbc.properties");
    //ClassPathResource resource = new ClassPathResource("config/jdbc.properties");
    Properties properties= PropertiesLoaderUtils.loadProperties(resource);
    System.out.println("jdbc.driver="+properties.getProperty("jdbc.driver"));
    System.out.println("jdbc.url="+properties.getProperty("jdbc.url"));
    System.out.println("jdbc.username="+properties.getProperty("jdbc.username"));
    System.out.println("jdbc.password="+properties.getProperty("jdbc.password"));
}

这里PropertiesLoaderUtils是spring-core.jar下面的,全路径名称:

org.springframework.core.io.support.PropertiesLoaderUtils

PropertiesLoaderUtils.loadProperties(resource)源码部分:

public static Properties loadProperties(EncodedResource resource) throws IOException {
    //创建一个Properties对象
    Properties props = new Properties();
    //处理文件内容并赋值给props
    fillProperties(props, resource);
    return props;
}

fillProperties(props, resource);方法:

public static void fillProperties(Properties props, EncodedResource resource) throws IOException {
    fillProperties(props, resource, ResourcePropertiesPersister.INSTANCE);
}

static void fillProperties(Properties props, EncodedResource resource, PropertiesPersister persister) throws IOException {
    InputStream stream = null;
    Reader reader = null;

    try {
        //省略不相关代码
        stream = resource.getInputStream();
        //获取InputStream
        persister.load(props, stream); 
    } finally {
        //关闭
    }
}

最后到PropertiesPersisterpersister.load(props, stream);

public void load(Properties props, InputStream is) throws IOException {
    props.load(is);
}

这里又回到Properties类中的load()方法里了。

绕了半天也只是获取InputStream的方式不同而已

第五种方式

接下来我们来使用PropertyResourceBundle读取InputStream流,实现配置文件读取。

代码实现:

public void readProperties5() throws IOException {
    InputStream inputStream = ClassLoader.getSystemResourceAsStream("jdbc.properties");
    //InputStream inputStream = ClassLoader.getSystemResourceAsStream("config/jdbc.properties");
    PropertyResourceBundle bundle = new PropertyResourceBundle(inputStream);
    System.out.println(bundle.getString("jdbc.driver"));
    System.out.println(bundle.getString("jdbc.url"));
    System.out.println(bundle.getString("jdbc.username"));
    System.out.println(bundle.getString("jdbc.password"));
}

好像也没什么,

PropertyResourceBundle源码

我们来看看 new PropertyResourceBundle(inputStream);源码部分:

public PropertyResourceBundle (InputStream stream) throws IOException {
    Properties properties = new Properties();
    properties.load(stream);
    lookup = new HashMap(properties);
}

这个构造方法里直接new了一个Properties对象。然后调用load方法解析。

所以,这种方式无非就是在Properties基础之上再封装了,也就是让我们使用起来更加方便。

PropertyResourceBundle类关系图

プロパティファイルを読み取る6つの方法、集めるのがおすすめ!

所以,上面代码中的bundle.getString("jdbc.url")其实调用的是父类中方法;

public final String getString(String key) {
    return (String) getObject(key);
}

最终调用到PropertyResourceBundlehandleGetObject()方法:

public Object handleGetObject(String key) {
    if (key == null) {
        throw new NullPointerException();
    }
    return lookup.get(key);
}

lookup就是一个HashMap:lookup = new HashMap(properties);

第六种方式

第五种方式中我们看到了ResourceBundle,接下来我们就是用ResourceBundle.getBundle()实现。

//不用输入后缀
public void readProperties6()  {
    ResourceBundle bundle=ResourceBundle.getBundle("jdbc"); 
    System.out.println(bundle.getString("jdbc.driver"));
    System.out.println(bundle.getString("jdbc.url"));
    System.out.println(bundle.getString("jdbc.username"));
    System.out.println(bundle.getString("jdbc.password"));
}

直接使用文件名称就可以了,不需要写文件后缀名。

java.util.ResourceBundle.getBundle(String baseName) 方法获取使用指定的基本名称,不需要文件后缀名,默认的语言环境和调用者的类加载器获取资源包。

  • baseName が null の場合、例外が報告されます。 NullPointerException
  • 指定されたベースが次の場合に報告されます。対応するリソース パッケージが見つかりませんでした。例外 MissingResourceException

#概要

上記は、Java でプロパティ ファイルを読み取る通常の 6 つの方法です。

以上がプロパティファイルを読み取る6つの方法、集めるのがおすすめ!の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はJava后端技术全栈で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。