手書きの分散構成センターは段階的に進行中です。
最近では、開発には基本的に Spring Boot が使用されており、プロジェクト内に application.properties
構成ファイルが存在することは誰もが知っています (一部は application も使用します) .yaml
、とにかく、構成情報の一部を保存するために使用されます)、通常は、データベース接続情報、サードパーティのインターフェイス情報 (キー、ユーザー名、パスワード、アドレスなど)、接続プール、Redis 構成情報、さまざまなサードパーティコンポーネント構成情報など。
単一サービス、または一部の小規模な分散アーキテクチャでも、プロジェクト構成は application.properties
構成ファイルに依存します (一部のプロジェクトには環境の区別がある場合があります。例: application -dev.properties
、application-pro.properties
など)。しかし、ビジネスが発展し、アーキテクチャがアップグレードされ続けるにつれて、各サービスに関係するサービス データと構成情報がますます増加し、リアルタイムでの独立した構成など、構成管理の要件もますます高くなります。情報、性別など
同時に、マイクロサービス アーキテクチャでは、構成管理、グレースケール パブリッシング、動的な電流制限、動的なダウングレード、および構成コンテンツのセキュリティやアクセス許可など、さまざまな環境でのその他の要件が関係する場合があります。構成やメンテナンスの方法がニーズを満たすのは困難です。
分散構成センターはこのような環境で誕生しました。
この記事では、まず Java でプロパティ設定ファイルを読み取るためのメソッドが何であるかを理解します。
構成ファイルがあることです。 <pre class="brush:php;toolbar:false;">jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=123456</pre>
ここで、上記の内容を取得したいとします。 Java コード内の構成ファイル。
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")); }
上記のコードについて話しましょう:
src/main/javaディレクトリにあり、リソース ファイルです。
src/main/resources/
ディレクトリにあります。は現在のクラスのディレクトリから検索されます。このファイルがクラスと同じディレクトリにない場合は見つかりません。
は、コンパイルされたクラス ディレクトリ全体から見つかります。また、Maven は、リソース ファイルをクラス フォルダーにパッケージ化して、見つけられるようにします。
ClassLoader
はクラス フォルダー全体から見つかるため、/
#プロパティを追加する必要はありません。
プロパティ: java.util.Properties
、このクラスは主に Java 構成ファイルを読み取るために使用されます。さまざまなプログラミング言語には独自のサポート構成があります。構成ファイル内の多くの変数は頻繁に変更されます。ユーザー構成を容易にするために、ユーザーはプログラム自体を終了せずに関連する変数設定を変更できます。 Java と同様に、その構成ファイルは多くの場合 .properties
ファイルであり、キーと値のペアの形式でパラメーターを構成します。
クラス関係図:
上記のクラス図から、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 == '=' || c == ':') && !precedingBackslash) { valueStart = keyLen + 1; hasSep = true; break; } else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) { valueStart = keyLen + 1; break; } if (c == '\\') { precedingBackslash = !precedingBackslash; } else { precedingBackslash = false; } keyLen++; } while (valueStart < limit) { c = lr.lineBuf[valueStart]; if (c != ' ' && c != '\t' && c != '\f') { if (!hasSep && (c == '=' || c == ':')) { 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 ポインター例外が報告されます 。 コードの残りの部分は最初の方法と同じなので、ここでは詳しく説明しません。
次に、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 { //关闭 } }
最后到PropertiesPersister
的persister.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基础之上再封装了,也就是让我们使用起来更加方便。
所以,上面代码中的bundle.getString("jdbc.url")
其实调用的是父类中方法;
public final String getString(String key) { return (String) getObject(key); }
最终调用到PropertyResourceBundle
的handleGetObject()
方法:
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 サイトの他の関連記事を参照してください。