Spring的加載機制導致不同SpringBoot啓動方式下@Value註解失效

問題參考鏈接https://blog.csdn.net/u011958281/article/details/81531676

背景:

項目使用application.yml文件自定義參數,我在配置文件中約定好一個"密碼",用來做請求的驗證,即請求方和響應方都需要配置一個一模一樣的"密碼",程序需要在運行的時候從配置文件中獲取這個"密碼",而目前最便捷的是使用@Value註解獲取配置文件中的值。

 

問題產生:

請求方在執行請求的時候,在請求服務器的@Controller層通過@Value註解獲取這個參數值。響應方通過@WebFilter在程序初始化的時候(InitFilter方法中)預先通過@Value註解獲取這個參數值。

在使用SpringBoot的內置Tomcat的時候,直接啓動@SpringBootApplication標註的啓動類,兩個地方都能夠獲取到參數值。

但是我的項目使用mvn插件打包相當麻煩,要使用更加便捷的使用外置Tomcat啓動,然後將生成的class文件直接扔在服務器上運行。所以只能使用外部的Tomcat來啓動我的SpringBoot程序。

這個時候,問題出現了:請求方的@Controller層中仍能正常通過@Value註解獲取參數值,而響應方的@WebFilter卻獲取失敗。

 

 

附請求方的Controller代碼和響應方的WebFilter代碼

@Controller
/**
    請求方相關的代碼就在這裏了
    直接通過main方法獲取肯定是拿不到參數值的,我也不是這個原因
*/
public class DoRequestController {


    @Value("${secret}")
    private String secret;


    @RequestMapping("getSecret")
    @ResponseBody
    public String getSecret(){
        //從springboot的配置文件中獲取@Value對應的參數值
        //SpringBoot的啓動類啓動或者外部的Tomcat啓動都可以如意拿取到
        System.out.println("secret: " + secret);
        return secret;
    }
}
/**
    這個是請求方的一個過濾器相關代碼
*/
@WebFilter(urlPatterns = { "/*"})
public class SignAuthenFilter implements Filter {

    @Value("${secret}")
    private String secret;


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //在初始化階段,我就通過輸出查看參數值是否成功獲取
        //詭異的是SpringBoot的啓動類啓動,能夠拿到
        //而外部Tomcat啓動,就拿不到~
        System.out.println("獲取secret: " + secret);
    }
    
    //doFilter方法不相干,所以沒有展示了
}
# 這個是application.yml文件中配置的參數
secret: XMTX

 

嘗試解決:

我在想是不是@Value註解抽風了,我又使用了網上搜集的,使用@Configration註解標註類、使用Enviroment織入需要獲取參數值的類中從而通過enviroment對象獲取參數值,等等。都不行~

 

導致問題的原因:

瀏覽參考鏈接的時候,發現該博主提到了"參數注入"的概念,也就是所謂的Spring的加載機制問題。在某些場景Spring做了優化(像前面的@WebFilter本來是無法通過@Value註解獲取參數值的,但是因爲SpringBoot是Spring的親兒子,所以我用SpringBoot的啓動類啓動可以正常獲取到參數值),而像我這種通過外置Tomcat的方式啓動,則沒有被優化~(也是我猜的,也許真是我哪裏沒寫對)。

 

解決方法:

參考該博主的,不能通過參數注入(SpringBoot啓動類啓動無視),而是使用初始化類的方式,將配置信息集中初始化。

/**
    該類的工作原理是利用Java的類加載機制
    你要通過該工具類獲取屬性值,則先要加載這個工具類的靜態代碼塊balabala~
    反正是他會先從配置文件中讀取屬性,然後返回給你
*/
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);
  }
}

使用方式就是如下,本來你要通過@Value註解獲取到的屬性值,現在通過該工具類直接通過對應的參數名拿

String secret = PropertyUtil.getProperty("secret");

 

感悟:

只能說自己的能力很差,這麼明顯的問題還在各種嘗試~

 

 

 

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