目錄
第一種方式" >第一種方式
##this. getClass().getResourceAsStream()" >##this. getClass().getResourceAsStream()
Properties " >Properties
Properties 常見方法" >Properties 常見方法
properties.load(inputStream)" >properties.load(inputStream)
getProperty(String key) " >getProperty(String key)
第二种方式 " >第二种方式
第三種方式 " >第三種方式
第四种方式 " >第四种方式
第五种方式 " >第五种方式
PropertyResourceBundle源码" >PropertyResourceBundle源码
PropertyResourceBundle类关系图" >PropertyResourceBundle类关系图
第六种方式 " >第六种方式
首頁 Java java教程 讀取properties檔案的6種方式,建議收藏!

讀取properties檔案的6種方式,建議收藏!

Aug 15, 2023 pm 04:03 PM
properties

手寫分散式設定中心一步一腳印正在進行中。

這年頭基本上都是使用Spring Boot開發,然後都知道在專案中會有一個application.properties設定檔(也有的是application.yaml,反正就是用來保存我們的一些設定資訊),通常我們會把一些設定資訊寫到properties檔案中,例如:資料庫連線資訊、第三方介面資訊(金鑰、使用者名稱、密碼、位址等) ,連接池、Redis配置資訊、各種第三方組件配置資訊等。

單體服務,甚至在一些小型的分散式架構中,專案的配置都是依賴一個application.properties設定檔來解決(可能有的專案會搞一個環境區分,例如:application-dev.propertiesapplication-pro.properties等)。不過,可能伴隨著業務的發展和架構不斷升級,服務的資料以及每個服務涉及到配置資訊會越來越多,並且對於配置管理的要求也是越來越高,例如配置資訊的即時性、獨立性等。

同時,我們在微服務架構下,可能還會涉及到不同環境下的組態管理、灰階發布、動態限流、動態降級等需求,包括對於設定內容的安全與權限,所以傳統的配置維護方式很難達到需求。

於是,分散式配置中心就在這樣的環境下產生了。

本文我們先搞清楚java中讀取properties設定文件,到底有哪些方法。

Java讀取properties設定檔的6種方式

需求背景

需求是我們專案中有個jdbc.properties 設定文件,內如下:

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
登入後複製

現在是想要在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/目錄下。

會從目前類別的目錄下去找,這個檔案如果不跟該類別在一個目錄下,就找不到。

會從編譯後的整個classes目錄下去找,maven也會把資源檔打包進classes資料夾,所以可以找到。

ClassLoader就是從整個classes資料夾找的,所以前面不用再加/

Properties

Properties:java.util.Properties,該類別主要用於讀取Java的配置文件,不同的程式語言有自己所支援的配置文件,設定檔中很多變數是經常改變的,為了方便使用者的配置,能讓使用者夠脫離程式本身去修改相關的變數設定。就像在Java中,其設定檔常為.properties文件,是以鍵值對的形式進行參數配置的。

類別關係圖:

讀取properties檔案的6種方式,建議收藏!

從上面的類別圖可以看到Properties類別繼承至Hashtable,相信大家都知道Hashtable是儲存key-value資料結構類,也剛好對應我們properties檔案內容也是key-value形式。

Properties 常見方法

#getProperty(String key)   :在此屬性清單中搜尋具有指定鍵的屬性。如果在此屬性清單中找不到該鍵,則會檢查預設屬性清單及其預設值(遞歸)。如果未找到該屬性,則該方法傳回預設值參數。

list(PrintStream out) 將此屬性清單列印到指定的輸出流。此方法對於調試很有用。

load(InputStream inStream)  :從輸入位元組流讀取屬性清單(鍵和元素對)。輸入流採用載入(Reader)中指定的簡單的面向行的格式,並假定使用ISO 8859-1字元編碼;即每個位元組是一個Latin1字元。不在Latin1中的字元和某些特殊字元在使用Unicode轉義符的鍵和元素中表示。此方法返回後,指定的流仍保持開啟狀態。

setProperty(String key, String  value) :呼叫 Hashtable 的方法 put 。他透過呼叫基底類別的put方法來設定 鍵值對。

store(OutputStream out, String comments) :將此Properties表中的此屬性清單(鍵和元素對)以適合使用load(InputStream)方法載入到Properties表的格式寫入輸出流。此Properties方法不會寫出此Properties表的defaults表中的屬性(如果有)。

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必須加/classpath下開始尋找
  • ##this.getClass( ).getClassLoader().getResourceAsStream() 預設就從classpath路徑下開始查找,加上/會報空指標異常
剩下的部分程式碼和第一種方式一樣,這裡就不在贅述了。

第三種方式

#接下來我們採用

ClassLoader類別的static方法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类关系图

讀取properties檔案的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中讀取properties檔案的6中方式。 #####################

以上是讀取properties檔案的6種方式,建議收藏!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

公司安全軟件導致應用無法運行?如何排查和解決? 公司安全軟件導致應用無法運行?如何排查和解決? Apr 19, 2025 pm 04:51 PM

公司安全軟件導致部分應用無法正常運行的排查與解決方法許多公司為了保障內部網絡安全,會部署安全軟件。 ...

如何使用MapStruct簡化系統對接中的字段映射問題? 如何使用MapStruct簡化系統對接中的字段映射問題? Apr 19, 2025 pm 06:21 PM

系統對接中的字段映射處理在進行系統對接時,常常會遇到一個棘手的問題:如何將A系統的接口字段有效地映�...

如何優雅地獲取實體類變量名構建數據庫查詢條件? 如何優雅地獲取實體類變量名構建數據庫查詢條件? Apr 19, 2025 pm 11:42 PM

在使用MyBatis-Plus或其他ORM框架進行數據庫操作時,經常需要根據實體類的屬性名構造查詢條件。如果每次都手動...

如何將姓名轉換為數字以實現排序並保持群組中的一致性? 如何將姓名轉換為數字以實現排序並保持群組中的一致性? Apr 19, 2025 pm 11:30 PM

將姓名轉換為數字以實現排序的解決方案在許多應用場景中,用戶可能需要在群組中進行排序,尤其是在一個用...

IntelliJ IDEA是如何在不輸出日誌的情況下識別Spring Boot項目的端口號的? IntelliJ IDEA是如何在不輸出日誌的情況下識別Spring Boot項目的端口號的? Apr 19, 2025 pm 11:45 PM

在使用IntelliJIDEAUltimate版本啟動Spring...

Java對像如何安全地轉換為數組? Java對像如何安全地轉換為數組? Apr 19, 2025 pm 11:33 PM

Java對象與數組的轉換:深入探討強制類型轉換的風險與正確方法很多Java初學者會遇到將一個對象轉換成數組的�...

電商平台SKU和SPU數據庫設計:如何兼顧用戶自定義屬性和無屬性商品? 電商平台SKU和SPU數據庫設計:如何兼顧用戶自定義屬性和無屬性商品? Apr 19, 2025 pm 11:27 PM

電商平台SKU和SPU表設計詳解本文將探討電商平台中SKU和SPU的數據庫設計問題,特別是如何處理用戶自定義銷售屬...

使用TKMyBatis進行數據庫查詢時,如何優雅地獲取實體類變量名構建查詢條件? 使用TKMyBatis進行數據庫查詢時,如何優雅地獲取實體類變量名構建查詢條件? Apr 19, 2025 pm 09:51 PM

在使用TKMyBatis進行數據庫查詢時,如何優雅地獲取實體類變量名以構建查詢條件,是一個常見的難題。本文將針...

See all articles