1. 程式人生 > >@Value取不到值,直接輸出了${name}字串

@Value取不到值,直接輸出了${name}字串

專案中經常會用到配置檔案,定義成properties的形式比較常見,為了方便使用一般在spring配置檔案中做如下配置:

<context:property-placeholder ignore-resource-not-found="true" location="classpath:xxxx.properties" file-encoding="utf-8"/>

這樣在程式程式碼中直接用@Value("${name}"),就能直接取到properties檔案中定義的變數值。

但是在專案中發現一個情況,在Controller中取不到這個值,直接輸出了${name}字串,並沒有解析出值,而在service中卻能取到。明顯在Controller中並沒有引入properties檔案中的變數,而被當做普通的字串處理了。

經過排查這個專案的web.xml中有2個配置檔案,1個spring-config.xml,1個spring-mvc.xml,其中spring-config.xml中定義有placeholder。

在web.xml中的配置片段如下:

<!-- Spring配置檔案開始 -->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
		classpath:spring-config.xml
	</param-value>
</context-param>

<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring配置檔案結束 -->

<!-- springmvc配置開始 -->
<servlet>
	<servlet-name>spring</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-mvc.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
	<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
	<servlet-name>spring</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- springmvc配置結束 -->
可以看到分為spring配置和springmvc配置2種。
其中spring配置以監聽器的形式引入,不指定xml配置檔案地址則預設查詢WEB-INF下的applicationContext.xml檔案。
springmvc則以servlet形式引入,當沒有指定引入的xml配置檔案地址時,則會自動引入WEB-INF下的[servlet-name]-servlet.xml檔案。本例中為spring-mvc.xml,引入順序為先引入spring配置,再引入servlet形式的springmvc配置。


值得注意的幾點是:

1、springmvc的配置檔案中可以直接用id引入spring配置檔案中定義的bean,但是反過來不可以。

2、每一個springmvc的配置檔案xxx-servlet.xml對應一個web.xml中的servlet定義。

3、當存在多個springmvc配置檔案時候,他們之間是不能互相訪問的。

在百度中別人的帖子中看到一段應該是官方的原文解釋,我摘抄過來並粗糙的直譯一下:
Spring lets you define multiple contexts in a parent-child hierarchy.
spring允許你定義多個上下文在父子繼承關係中。
The applicationContext.xml defines the beans for the "root webapp context", i.e. the context associated with the webapp.
applicationContext.xml檔案是為了"根webapp應用上下文"定義bean,也就是說它的上下文是和webapp想關聯的。
The spring-servlet.xml (or whatever else you call it) defines the beans for one servlet's app context. There can be many of these in a webapp, 
spring-servlet.xml檔案(或是其他的你習慣的稱呼)是為了一個servlet應用上下文呢定義bean。在一個webapp中可以有多個此配置檔案。
one per Spring servlet (e.g. spring1-servlet.xml for servlet spring1, spring2-servlet.xml for servlet spring2).
每一個spring的servlelt(例如: 名為spring1的servlet擁有配置檔案spring1-servlet.xml, 名為spring2的servlet擁有配置檔案spring2-servlet.xml)。
Beans in spring-servlet.xml can reference beans in applicationContext.xml, but not vice versa.
在spring-servlet.xml中定義的bean可以直接引用在applicationContext.xml中定義的bean,但是反過來不可以。
All Spring MVC controllers must go in the spring-servlet.xml context.
所有springmvc的Controller必須在spring-servlet.xml對應的上下文中執行。
In most simple cases, the applicationContext.xml context is unnecessary. It is generally used to contain beans that are shared between all servlets
在大多數簡單的情況下, applicationContext.xml對應的上下文並不必須。它通常用來包含那些bean用來在webapp中所有servlet之間共享。
in a webapp. If you only have one servlet, then there's not really much point, unless you have a specific use for it.
如果你只有一個servlet, 那麼實際沒有什麼必要定義applicationContext.xml, 除非你有特別應用。

解決:

回到最開始的@Value取不到值的問題,現在可以清楚是由於Controller是定義在springmvc的servlet配置檔案中的,故只需要將placeholder重新在springmvc的配置中配置一遍,Controller中的@Value註解便能取到值了。