Spring MVC框架的高級(jí)配置(下)
上文介紹Spring MVC框架配置時(shí)遇到的問(wèn)題,以下是解決方案。
解決方案
同步Bean屬性
這個(gè)問(wèn)題的一種可行的解決方案是將所有特定于主機(jī)的參數(shù)都放到普通的Java屬性文件中,使用Spring的PropertyPlaceHolderConfigurer類,將這些參數(shù)寫(xiě)入Bean屬性中。
使用這一解決方案,我們可以生成如下的屬性文件(/Web-INF/JDBC.properties):
- jdbc.driver=org.postgresql.Driver
- jdbcjdbc.url=jdbc:postgresql://localhost/test
- jdbc.user=postgres
- jdbc.password=
我們的Bean配置如下:
- <bean id="propertyConfigurer"
- class="org.springFramework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="location">
- <value>/WEB-INF/jdbc.properties</value>
- </property>
- </bean>
- <bean id="dataSource"
- class="org.springframework.jdbc.datasource.DriverManagerDataSource">
- <property name="driverClassName">
- <value>${jdbc.driver}</value>
- </property>
- <property name="url">
- <value>${jdbc.url}</value>
- </property>
- <property name="username">
- <value>${jdbc.user}</value>
- </property>
- <property name="password">
- <value>${jdbc.password}</value>
- </property>
- </bean>
如上所述,我們定義了一個(gè)PropertyPlaceholderConfigurer類的實(shí)例,并將其位置屬性設(shè)置為我們的屬性文件。該類被實(shí)現(xiàn)為Bean工廠的后處理器,并將使用定義在文件中的屬性來(lái)代替所有的占位符(${...}value)。
利用這種技術(shù),我們可以從applicationContext.XML中移除所有特定于主機(jī)的配置屬性。通過(guò)這種方式,我們可以自由地為該文件添加新的Bean,而不必?fù)?dān)心特定于主機(jī)屬性的同步性。這樣可以簡(jiǎn)化生產(chǎn)部署和維護(hù)。
同步性連接
上面的技術(shù)解決了***個(gè)問(wèn)題,可是如果您計(jì)劃修改不同應(yīng)用程序部署之間的Bean連接,這一技術(shù)便不很適合。針對(duì)這一問(wèn)題的一個(gè)解決方案便是額外創(chuàng)建一個(gè)名為applicationContext-[hostname].xml 的XML定義文件。其中[hostname]是部署應(yīng)用程序的主機(jī)的名稱。例如,在本地的機(jī)器上,這個(gè)文件通常名為 applicationContext-localhost.xml,而在部署時(shí),它可能更名為applicationContext- somehost.com.xml。
可以猜測(cè),這一文件必須包括特定于某一主機(jī)的所有配置Bean。在本文中,我們將假設(shè)dataSource bean定義將位于這類文件中,而不是通用的applicationContext.xml定義。當(dāng)然,這種機(jī)制與前者并非沖突,但是為了更加簡(jiǎn)單明了,我們將只關(guān)注這種方法。
既然我們已經(jīng)有了特定的配置,下面我們就來(lái)討論一下如何將其整合到整個(gè)Spring MVC框架配置概念中。要達(dá)到這一目的,可以有許多方法,我們將詳細(xì)地一一說(shuō)明。但首先,我們應(yīng)該注意到,由于有些Bean可能位于獨(dú)立的配置文件中,因此在 applicationContext.xml中,所有對(duì)它們的局部引用都必須更換成全局名稱。
例如,如下引用:
- <property name="someProperty">
- <ref local="someBean"/>
- </property>
應(yīng)更改為:
- <property name="someProperty">
- <ref bean="someBean"/>
- </property>
在這之后,我們有很多可以添加額外的資源以用于配置的方式。其中最明顯的就是使用<import>標(biāo)簽將這一額外資源包含在 applicationContext.xml配置文件中。使用時(shí),要將該標(biāo)簽放在applicationContext.xml文件開(kāi)頭。例如:
- <import resource="applicationContext-somehost.com.xml"/>
現(xiàn)在,在獨(dú)立的XML定義文件和普通的應(yīng)用程序上下文定義文件中的所有通用Bean定義都有了特定于主機(jī)的連接。由于大多數(shù)的Bean都不是特定于主機(jī)的,因此我們可以像處理Web應(yīng)用程序中的其他資源一樣自由地處理applicationContext.xml文件,并可以通過(guò)合適的版本控制系統(tǒng)與其進(jìn)行同步。
但是,上述方法也有一定的弊端。如果您想保留不同XML文件的不同配置,就仍然必須擔(dān)心applicationContext.xml的同步性,因?yàn)橘Y源的名稱必須根據(jù)不同服務(wù)器進(jìn)行更改。雖然與原有的解決方案相比有了很大提高,只需更改文件名,但是這還是需要開(kāi)發(fā)人員的手動(dòng)協(xié)助。
由于與applicationContext.xml相比,主機(jī)配置不需如此頻繁地進(jìn)行更改,因此下一步便是將主機(jī)配置移動(dòng)到web.xml文件中(如果可能的話)。幸運(yùn)的是,我們有一個(gè)可用的解決方案??匆幌孪旅骊P(guān)于web.xml配置的片斷:
- <listener>
- <listener-class> org.springFramework.web.context.ContextLoaderListener
- </listener-class>
- </listener>
- <context-param>
- <param-name>contextConfigLocation
- </param-name>
- <param-value> /WEB-INF/applicationContext.xml /WEB-INF/ applicationContext-somehost.com.xml
- </param-value>
- </context-param>
正如您所看到的,除了web.xml文件中常有的ContextLoaderListener之外,我們還添加了 contextConfigLocation上下文參數(shù)配置。這一參數(shù)用于指示框架查找這些配置文件的位置。如果這一參數(shù)被省略,則Spring就只能到 applicationContext.xml中查找。這里我們也定義了特定于主機(jī)的配置文件來(lái)使用。
利用這種方法,我們將所有特定于主機(jī)的配置從applicationContext.xml文件中移除,這樣便減輕了其在不同應(yīng)用程序部署中的同步性。
如果這種方法成為您的新習(xí)慣,您還可以使其更加靈活。通過(guò)遵守下列指令,也可以將特定于主機(jī)的配置從web.xml文件中移除。
為此,需要?jiǎng)?chuàng)建特定于我們的應(yīng)用程序上下文的類:
- package net.nighttale.spring.util;
- import Java.net.InetAddress;
- import org.springframework.web.context.support.XmlWebApplicationContext;
- public class PerHostXmlWebApplicationContext
- extends XmlWebApplicationContext ...{
- protected String[] getDefaultConfigLocations() ...{
- String hostname = "localhost";
- try ...{
- hostname = InetAddress.getLocalHost().getHostName();
- } catch (Exception e) ...{
- }
- String perHostConfiguration = DEFAULT_CONFIG_LOCATION_PREFIX
- + "applicationContext-"
- + hostname
- + DEFAULT_CONFIG_LOCATION_SUFFIX
- ;
- logger.debug(
- "Adding per host configuration file: "
- + perHostConfiguration
- );
- if (getNamespace() != null) ...{
- return new String[] ...{
- DEFAULT_CONFIG_LOCATION_PREFIX
- + getNamespace()
- + DEFAULT_CONFIG_LOCATION_SUFFIX
- , perHostConfiguration};
- }
- else ...{
- return new String[] ...{
- DEFAULT_CONFIG_LOCATION
- , perHostConfiguration};
- }
- }
- }
這個(gè)類拓展了Spring中常被作為默認(rèn)值使用的XmlWebApplicationContext。 XmlWebApplicationContext類將Web應(yīng)用程序的配置從XML定義文件中復(fù)制過(guò)來(lái)。默認(rèn)情況下,它可以配置來(lái)自 applicationContext.xml和[Servlet-name]-servlet.xml文件中的應(yīng)用程序。這個(gè)類執(zhí)行的惟一一項(xiàng)額外任務(wù)便是獲取它所在的主機(jī)名稱,并將applicationContext-[hostname].xml文件添加到配置文件列表中。
為了使用這個(gè)類,我們需要對(duì)其進(jìn)行編譯,將其包含在類途徑中,并指示Spring框架使用它。前兩步非常簡(jiǎn)單,我們就不在此贅述。我們可以指示Sping通過(guò)contextClass上下文參數(shù)來(lái)使用它。除了web.xml文件中的原有配置,我們還可以添加下列內(nèi)容:
- <context-param>
- <param-name>contextClass</param-name>
- <param-value> net.nighttale.spring.util.PerHostXmlWebApplicationContext
- </param-value>
- </context-param>
如果我們使用這一配置片斷,將會(huì)有三個(gè)文件被用于初始化這個(gè)框架:[servlet-name]-servlet.xml、applicationContext-[hostname].xml以及applicationContext.xml。
正如您所看到的,applicationContext.xml和web.xml文件已經(jīng)完全擺脫了任何特定的配置細(xì)節(jié),而且您也不必?fù)?dān)心會(huì)在更新應(yīng)用程序時(shí)破壞配置。
但是,這種方法有一個(gè)不足之處。因?yàn)?,不論是否?huì)使用,都需要在應(yīng)用程序部署中有第三個(gè)配置文件。在這種情況下,便不需要特定于主機(jī)的配置。例如:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
- <beans>
- </beans>
***,需要知道應(yīng)用程序上下文類需要查找的特定主機(jī)名。檢查主機(jī)名稱的最簡(jiǎn)單的方法是在機(jī)器上運(yùn)行下列代碼:
- System.out.println(InetAddress.getLocalHost().getHostName());
可以將其作為Java代碼執(zhí)行,也可在喜歡使用的腳本語(yǔ)言(如BeanShell或Groovy)中作為一個(gè)具有Java風(fēng)格語(yǔ)法的腳本執(zhí)行。在獲取了主機(jī)的名稱之后,應(yīng)該創(chuàng)建一個(gè)默認(rèn)的/WEB-INF/applicationContext-[hostname].xml空文件夾(如我們上面所定義的),然后便可以開(kāi)始了。
結(jié)束語(yǔ)
在本文中,我們提供了一系列的配置技巧,讓您在使用Spring MVC框架完成日常工作的時(shí)候更加輕松。如果您希望知道如何維護(hù)各種Web應(yīng)用程序部署,可以試著找出最適合您的開(kāi)發(fā)過(guò)程的解決方案。您的生活會(huì)更為輕松。
【編輯推薦】