問題參考鏈接: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");
感悟:
只能說自己的能力很差,這麼明顯的問題還在各種嘗試~