天天看點

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,如下所示:

    [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

    */@Configuration@PropertySource("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提供的配置檔案讀取更加的靈活強大,也符合架構本身快速開發的思想。
  • 不足之處,歡迎指正,謝謝~

繼續閱讀