Spring Boot 學習系列(07)—properties檔案讀取
此文已由作者易國強授權網易雲社群釋出。
歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。
傳統的properties讀取方式
一般的,我們都可以自定義一個xxx.properties檔案,然後在工程的xml配置檔案中注入相關的配置bean,示例如下:
<context:property-placeholder location="classpath:config/${spring.profiles.active:unknown}/zk.properties" order="1" ignore-unresolvable="true" ignore-resource-not-found="true"/><bean id="kafkaProps" class="org.springframework.beans.factory.config.PropertiesFactoryBean" > <property name="ignoreResourceNotFound" value="true"/> <property name="location" value="classpath:config/${spring.profiles.active:unknown}/kafka.properties"/> <property name="fileEncoding" value="UTF-8" /></bean>
然後就可以在我們需要使用的地方之間使用xxx.properties中配置的資訊。在Java和xml中使用示例分別如下:
@Servicepublic class KafkaHotPostConsumer {@Value("#{kafkaProps['light.kafka.bootstrap.servers']}") private String KAFKA_BOOTSTRAP_SERVERS;
<dubbo:registry id="faDataCenter" protocol="zookeeper" address="${zookeeper.servers}" group="${zookeeper.group.dataCenter}"/><bean id="kafkaClientL" class="com.netease.mq.kafka.KafkaProduerClient"> <property name="level" value="low"></property> <property name="brokerList" value="#{kafkaProps['light.kafka.bootstrap.servers']}"></property></bean>
當然我們也可以針對某一個特定的配置檔案,編寫操作的PropertiesUtil類來進行操作,在此不再展開。
Spring Boot的properties讀取方式
在Spring Boot中對於配置檔案的讀取方式比較靈活,分別演示如下。
application.properties
這個配置檔案是預設的核心配置檔案,原則上來說,如果有需要配置的資訊可以直接存放在這裡,不建議自定義配置檔案存放,這樣可以達到方便快速使用的目的。對於此配置檔案下的資訊讀取非常簡單,如果是在配置檔案中需要獲取已定義的資訊,則可直接使用,如下所示:
#服務啟動埠server.port=7777#自定義欄位custom.url=http://localhost:${server.port}/query.do
在Java程式碼中使用也非常簡單,可以通過@Value註解或者通過Environment類來獲取當前環境中載入的配置資訊,示例如下:
@Value("${server.port}")private String port;@AutowiredEnvironment env;@GetMapping("/")public String hello(){ System.out.println("my server port is =" + port); System.out.println("custom url = " + env.getProperty("custom.url","defaultValue")); return "hello,world"; }
當然,如果我們需要自定義properties檔案來存取我們想要的資訊也是支援的。實際上,不論是application.properties還是自定義的demo.properties檔案,最終都會轉化對映一個具體的配置類,而我們實際上在程式碼中操作的就是這個配置類。下面我們演示下如何自定義配置檔案。
新建配置檔案demo.properties,如下所示:
demo.username=demo [email protected]
然後編寫對應的對映類,如下所示,實際上,上面也有介紹,我們也可以使用@Value註解獲取配置資訊,不過用environment的方式獲取,可以指定預設值。這裡我們需要注意加入@Configuration的註解,然後指定對應的配置檔案路徑即可。
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.PropertySource;import org.springframework.core.env.Environment;/** * 演示自定義配置檔案讀取 * <p> * * @date 2017/10/18 10:57. * @author bjyiguoqiang */@[email protected]("classpath:demo.properties")public class DemoProperties { @Autowired Environment environment; public String getUsername() { return environment.getProperty("demo.username"); } public String getEmail() { return environment.getProperty("demo.email"); } }
接下來我們就可以直接操作DemoProperties這個類來讀取配置資訊了。示例如下:
@ResourceDemoProperties demoProperties; ....../** * 1、核心配置檔案的讀取示例 * </p> * 2、自定義配置檔案的讀取示例 * * @return*/@GetMapping("/")public Object hello() { //讀取自定義配置檔案 String email = demoProperties.getEmail(); String username = demoProperties.getUsername(); logger.info("demo properties : email={},username={}", email, username); }
當然我們也可以在啟動程式jar的時候指定外部的配置檔案,如果程式在啟動時就會優先載入外部的這個配置檔案,示例如下:
java -jar demo.jar --spring.config.location=/opt/config/application.properties
遇到的問題
正常情況下,通過上面列舉的讀取方式基本能滿足我們的使用需求,但也存在特殊的情況。比如我們很多場景還是會引入第三方的jar包或需要自己封裝jar包來提供給其他服務使用,那麼這個時候不能強依賴spring boot框架的讀取方式。
如果在我們的jar包需要獲取某一特定的配置檔案中的資訊該怎麼辦呢?這裡就需要注意了,不然就會掉進坑裡。這也是我們實際遇到的一個問題,原來在程式碼中讀取配置檔案程式碼示例如下:
BufferedInputStream in = null; URL resourceFile = Thread.currentThread().getContextClassLoader().getResource("/demo.properties");String path = resourceFile.getPath();try { in = new BufferedInputStream(new FileInputStream(path)); } catch (FileNotFoundException e) { //.....} PropertyResourceBundle resource = null;try { resource = new PropertyResourceBundle(in); } catch (IOException e) { //.....} HashMap props = new HashMap(); Iterator uriArray = resource.keySet().iterator();String strTmp;while(uriArray.hasNext()) { strTmp = (String)uriArray.next(); props.put(strTmp, resource.getObject(strTmp)); }String demoEmail = (String)props.get("demo.email");
上面的程式碼在非Spring Boot專案中執行是沒有什麼問題的,我們只需要在resources下存放demo.properties檔案即可正常讀取。但在spring boot專案中讀取卻會出現問題。丟擲的錯誤很直觀,就是提示在classpath下找不到對應的檔案。
出現問題的根本原因在於Spring Boot 如果以jar包的形式進行部署,classpath路徑會被替換成jar:file:/xxx/xxx/classess!,最終生成的資源路徑為jar:file:/xxx/xxx/classess!/xx/xx.xx
因為服務是通過jar包啟動的,通過系統的檔案系統並不能獲取到我們想要的檔案(比如demo.propeties),所有使用諸如new File(path)的形式就會出現問題
我們可以變更以流的方式讀取來獲取jar中的類資原始檔。示例程式碼如下:
//直接返回StreamInputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("demo.properties"); BufferedInputStream in = new BufferedInputStream(inputStream); PropertyResourceBundle resource = null;try { resource = new PropertyResourceBundle(in); } catch (IOException e) { //.....} HashMap props = new HashMap(); Iterator uriArray = resource.keySet().iterator();String strTmp;while(uriArray.hasNext()) { strTmp = (String)uriArray.next(); props.put(strTmp, resource.getObject(strTmp)); }String demoEmail = (String)props.get("demo.email");
最後
通過上面所述,結合大家親自實踐後,應該不難發現Spring Boot提供的配置檔案讀取更加的靈活強大,也符合框架本身快速開發的思想。
不足之處,歡迎指正,謝謝~
更多網易技術、產品、運營經驗分享請點選。
相關文章:
【推薦】 驗證碼示例程式碼演示——以php為例
【推薦】 分散式儲存系統可靠性系列二:系統估算示例