首先,先簡述一下遇到的問題,在程式中看到了這樣的一段程式碼:

String cmsRoot = System.getProperty(rootKey);

查看了一下api是這樣描述的:獲取用指定鍵描述的系統屬性

百度了一下,是這樣子的:

Java.version

Java 執行時環境版本

java.vendor

Java 執行時環境供應商

java.vendor.url

Java 供應商的 URL

java.home

Java 安裝目錄

java.vm.specification.version

Java 虛擬機器規範版本

java.vm.specification.vendor

Java 虛擬機器規範供應商

java.vm.specification.name

Java 虛擬機器規範名稱

java.vm.version

Java 虛擬機器實現版本

java.vm.vendor

Java 虛擬機器實現供應商

java.vm.name

Java 虛擬機器實現名稱

java.specification.version

Java 執行時環境規範版本

java.specification.vendor

Java 執行時環境規範供應商

java.specification.name

Java 執行時環境規範名稱

java.class.version

Java 類格式版本號

java.class.path

Java 類路徑

java.library.path

載入庫時搜尋的路徑列表

java.io.tmpdir

預設的臨時檔案路徑

java.compiler

要使用的 JIT 編譯器的名稱

java.ext.dirs

一個或多個擴充套件目錄的路徑

os.name

作業系統的名稱

os.arch

作業系統的架構

os.version

作業系統的版本

file.separator

檔案分隔符(在 UNIX 系統中是“/”)

path.separator

路徑分隔符(在 UNIX 系統中是“:”)

line.separator

行分隔符(在 UNIX 系統中是“/n”)

user.name

使用者的賬戶名稱

user.home

使用者的主目錄

user.dir

使用者的當前工作目錄

根本沒有我在程式碼中見到的這個key,然後我就在整個系統中搜這個key值,發現在web.xml中有這個key值,所以肯定是這樣影響的了,如下所示:

<!-- 以Listener方式啟動spring -->
	<listener>
		<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
	</listener>

	<context-param>
		<param-name>webAppRootKey</param-name>
		<param-value>shishuo.cms.root</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.util.WebAppRootListener</listener-class>
	</listener>

但是好久不用了,忘記了context-param和listener之間的關係了,所以先複習一下web.xml中的context-param:

context-param用來宣告應用範圍(整個WEB專案)內的上下文初始化引數,這個怎麼來理解呢,其實可以根據上面這個WebAppRootListener來理解,使用Eclipse開啟WebAppRootListener的原始碼,如圖:

public class WebAppRootListener implements ServletContextListener {

	public void contextInitialized(ServletContextEvent event) {
		WebUtils.setWebAppRootSystemProperty(event.getServletContext());
	}

	public void contextDestroyed(ServletContextEvent event) {
		WebUtils.removeWebAppRootSystemProperty(event.getServletContext());
	}

}

contextInitialized方法是實現介面ServletContextListener中的方法,通過名稱我們可以很容易理解這是一個初始化的方法,開啟WebUtils.setWebAppRootSystemProperty方法,如下所示:

public static void setWebAppRootSystemProperty(ServletContext servletContext) throws IllegalStateException {
		Assert.notNull(servletContext, "ServletContext must not be null");
		String root = servletContext.getRealPath("/");
		if (root == null) {
			throw new IllegalStateException(
				"Cannot set web app root system property when WAR file is not expanded");
		}
		String param = servletContext.getInitParameter(WEB_APP_ROOT_KEY_PARAM);
		String key = (param != null ? param : DEFAULT_WEB_APP_ROOT_KEY);
		String oldValue = System.getProperty(key);
		if (oldValue != null && !StringUtils.pathEquals(oldValue, root)) {
			throw new IllegalStateException(
				"Web app root system property already set to different value: '" +
				key + "' = [" + oldValue + "] instead of [" + root + "] - " +
				"Choose unique values for the 'webAppRootKey' context-param in your web.xml files!");
		}
		System.setProperty(key, root);
		servletContext.log("Set web app root system property: '" + key + "' = [" + root + "]");
	}

這個類和方法是Spring中web包中封裝好的,所以應該是很靠譜的方法和類了,關鍵是這句話String param = servletContext.getInitParameter(WEB_APP_ROOT_KEY_PARAM);那麼WEB_APP_ROOT_KEY_PARAM又等於什麼呢,如下:

public static final String WEB_APP_ROOT_KEY_PARAM = "webAppRootKey";

原來就是我們在context-param中配置的值,這是怎麼回事呢?

因為web.xml在載入的時候會按照

context-param >> listener  >> fileter  >> servlet

這個順序來載入,所以context-param載入之後,就會儲存在ServletContext的例項物件中了,getInitParameter方法可以獲取到其中的值,

System.setProperty(key, root);

經過一系列的判斷,最終把這裡的值當作key來儲存應用的路徑