Spring boot中參數注入,@Value失效以及解決方案

Spring boot中參數注入,@Value失效以及解決方案

2018年08月09日 10:15:06 小瘋子_的博客 閱讀數 9907

 版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/u011958281/article/details/81531676

問題

項目中我們都要要儘量避免將參數直接寫進程序裏,這樣一旦需要需要修改配置,我們可以只需要在配置文件裏做修改,而不必在程序裏找,這樣可以避免很多錯誤,個人項目可能不會注意這一點,但是需要上線發佈的項目,Configure配置文件就顯得非常重要!現在很多公司其實都有這方面的應用,甚至有專門的中間件可以專門管理配置文件,即時生效,不必去上線修改參數,這不是我們今天說的重點。先看內容:

application-dev.properties

#URL
confirmURL=http://127.0.0.1:8081/confirm
  • 1
  • 2

這裏寫圖片描述
然後在Controller類裏面通過@Value將參數注入進來,最後的確成功了。因此基於此經驗,我便在其他使用的類裏面也採用這樣的方式注入參數,但是發現去失效了,報錯爲NULL,說明參數並沒有我們料想的被注入進來。

原因

這是爲什麼呢?爲什麼在Controller類就成功了?在其他類裏面我嘗試過@Service,@Component,@Configure,但是我沒有成功,經過查詢,原來,在使用這些參數生成Bean類的時候,我們注入的參數還沒有生效,因此獲取不到,而不是由於參數注入的問題,而在某些場景,spring可能做了優化,是的參數優先注入,再生成Bean。那麼有沒有好的方法可以解決這個問題呢?

方案

首先,我們的參數的直接注入是肯定不行了,那麼我們就採用初始化類的方式,將配置信息集中初始化。

public class PropertyUtil {

  private static final Logger logger = LoggerFactory.getLogger(PropertyUtil.class);
  private static Properties props;

  static {
    loadProps();
  }

  synchronized static private void loadProps() {
    logger.info("start to load properties.......");
    props = new Properties();
    InputStream in = null;
    try {

      in = PropertyUtil.class.getClassLoader().
      getResourceAsStream("application.properties");
      props.load(in);
      logger.info(name);
    } catch (FileNotFoundException e) {
      logger.error("properties not found!");
    } catch (IOException e) {
      logger.error("IOException");
    } finally {
      try {
        if (null != in) {
          in.close();
        }
      } catch (IOException e) {
        logger.error("properties close Exception!");
      }
    }
    // logger.info(props);
    logger.info("load properties over...........");
  }

  public static String getProperty(String key) {
    if (null == props) {
      loadProps();
    }
    return props.getProperty(key);
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

通過Util類我們一次行加載參數,在需要獲取的地方,直接通過

private static String 
   unsubscribeUrl = PropertyUtil.getProperty("unsubscribeUrl");
  • 1
  • 2

這樣就可以獲取我們所需要的參數了,直接定義爲靜態變量,一次讀取,後面都可以直接使用。

引申

在Spring boot中參數配置有三個 application.properties, application-dev.properties, application-prod.properties

application.properties

spring.profiles.active=dev
  • 1

通過在這裏修改dev 或者 prod 我可以配置兩套配置,一套用於產品,一套是開發,那麼我如果來根據我配置的信息來讀取不同的配置呢,這又讓我頭疼了,看着代碼,我想到,既然他可以讀取配置文件了,那麼我爲何不先獲取一下 application.properties裏面的信息,然後看dev,或者prod來加載不同的配置呢,因此,我加了一段判斷代碼:

 in = PropertyUtil.class.getClassLoader().getResourceAsStream("application.properties");
      props.load(in);
      String name = getProperty("spring.profiles.active");
      if (name.equals("dev")) {
        in = PropertyUtil.class.getClassLoader().getResourceAsStream("application-dev.properties");
      } else if (name.equals("prod")) {
        in = PropertyUtil.class.getClassLoader().getResourceAsStream("application-prod.properties");
      }
      props.load(in);
      logger.info(name);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

通過測試,name的確是我 在application.properties配置的信息,因此,這具很好的解決了兩套配置,在線下測試跟發佈,我只需要修改一個配置文件就可以完成轉換,節省時間的同時,也避免了錯誤發生,很多上線的問題都是因爲配置的問題,因此這個問題一定要小心,當然還有很多方案,後面接觸到我會繼續總結,最近在代碼的重構,發現自己的代碼有很多問題。

@Component
public class ExchangeServiceUtil {

  private static String mailServer;
  private static String user;
  private static String password;
  private Logger logger = LoggerFactory.getLogger(this.getClass());

  @Autowired
  private ExchangeServiceUtil(@Value("${spring.EWS.mailServer}") String mailServer,
      @Value("${spring.EWS.user}") String user,
      @Value("${spring.EWS.password}") String password) {
    this.mailServer = mailServer;
    this.user = user;
    this.password = password;
  }

  private static ExchangeServiceUtil instance = new ExchangeServiceUtil(mailServer, user, password);

  public static ExchangeServiceUtil getExchangeServiceUtil() {
    return instance;
  }

  public ExchangeService getExchangeService() throws URISyntaxException {
    ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
    ExchangeCredentials credentials = new WebCredentials(user, password);
    service.setCredentials(credentials);
    service.setUrl(new URI(mailServer));
    //    service.autodiscoverUrl("<your_email_address>");
    return service;
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

我通過構造函數的方式,也成功的把參數注入到了裏面,這個方法也是偶然接觸到的,在某些工具,比如數據池,這是微軟的郵件發送配置,都是可以採用這樣的方法,構造函數可以加載參數,然後在生成Bean,很好的避開了那個問題,這個問題我還會繼續深究,看看有什麼發現,如果你有高見,歡迎留言!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章