1. 程式人生 > >精通Spring+4.x++企業開發與實踐之Spring容器高階主題

精通Spring+4.x++企業開發與實踐之Spring容器高階主題

Spring容器高階主題

內部工作機制

Spring的AbstractApplicationContext是ApplicationContext的抽象實現類,該抽象類的refresh()方法定義了Spring容器在載入配置檔案後的各項處理過程這些處理過程清晰的刻畫了Spring容器啟動時所執行的各項操作。

synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		prepareRefresh();
		//1.初始化BeanFactory:根據配置檔案例項化BeanFactory,在obtainFreshBeanFactory()方法中,
		//首先呼叫refreshBeanFactory()重新整理BeanFactory,然後呼叫getBeanFactory()獲取BeanFactory,
		//這兩個方法都是由具體子類實現的。在這一步,Spring將配置i檔案資訊裝入容器的Bean定義登錄檔(
		//BeanDefinitionRegistry)中,但此時Bean還未初始化。
		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);
			//2.呼叫工廠後處理器:根據反射機制從BeanDefinitionRegistry中找出所有實現了
			//BeanFactoryPostProcessor介面Bean,並且呼叫其postProcessBeanFactory()介面方法。
			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);
			//3.註冊Bean後處理器:根據反射機制從BeanRegistry中找出所有實現了BeanPostProcessor介面的
			//的Bean,並且將它們註冊到容器Bean後處理器的登錄檔中。
			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);
			//4.初始化訊息源:初始化容器的國際化訊息資源。
			// Initialize message source for this context.
			initMessageSource();
			//5.初始化應用上下文事件廣播器
			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();
			//6.初始化其他特殊的Bean:這是一個鉤子方法,子類可以藉助這個方法執行一些特殊的操作,如
			//AbstractRefreshableWebApplicationContext就使用該方法執行初始化ThemeSource的操作
			// Initialize other special beans in specific context subclasses.
			onRefresh();
			//7.註冊事件監聽
			// Check for listener beans and register them.
			registerListeners();
			//8.初始化所有單例項的Bean,使用懶載入模式的Bean除外:初始化Bean之後將它們放入Spring容器的
			緩衝池。
			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);
			//9.完成重新整理併發布容器重新整理事件:建立上下文重新整理時間,時間廣播器負責將這些時間廣播到每個註冊的
			//時間監聽器中
			// Last step: publish corresponding event.
			finishRefresh();
		}

		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}

			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		}

		finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}

IoC的流水線圖:

1.ResourceLoader從儲存介質載入Spring配置資訊,並使用Resource表示這個配置檔案資源。

2.BeanDefinitionReader讀取Resource所指向的配置檔案資源,然後解析配置我呢見。配置檔案中的每個<bean>解析成一個BeanDefinition物件,並儲存到BeanDefinitionRegistry中。

3.容器掃描BeanDefinitionRegistry中的BeanDefinition,使用Java反射機制自動識別出Bean工廠的後處理器(實現BeanFactoryPostProcessor介面的Bean),然後呼叫這些Bean工廠後處理器對BeanDefinitionRegistry中的BeanDefinition進行加工處理。主要完成以下兩項工作。
		1. 對使用佔位符的<bean>元素進行解析,得到最終的配置值。這意味著對一些半成品式的BeanDefinition物件進行架構處理並得到成品的BeanDefinition物件。
		2.對BeanDefinitionRegistry中的BeanDefinition進行掃描,通過Java反射機制找出所有屬性編輯器的Bean(實現了java.beans.PropertyEditor介面的Bean),並自動將它們註冊到Spring容器的屬性編輯器登錄檔中(org.springframework.beans.PropertyEditorRegistry).
4.Spring容器從BeanDefinitionRegistry中取出後加工後的BeanDefinition,並呼叫InstantiationStrategy著手進行Bean例項化的工作。
5.例項化Bean時,Spring容器使用BeanWrapper對Bean進行封裝,BeanWrapper提供了很多以Java反射機制操作Bean的方法,它將結合Bean的Definition及容器中的屬性編輯器,完成屬性注入工作。
6.利用容器註冊的Bean進行後處理器(實現BeanPostProcessor介面的Bean)對已經完成屬性設定工作的Bean進行後續的加工,直接裝配出一個準備就緒的Bean.

Spring組建按其所承擔的角色可劃分未兩類。

物料元件:Resource,BeanDefinition,PropertyEditor及最終的Bean等,它們時加工流程被加工,被消費的組建,就像流水線上被加工的物料一樣。
裝置元件:ResourceLoader,BeanDefinitonReader,BeanFactoryPostProcessor,InstantiationStrategy及BeanWrapper等。它們就像流水線上不同環節的裝置加工設定,對物料組建進行加工處理。

BeanDefinition

org.springframework.beans.factory.config.BeanDefinition是配置檔案<bean></bean>元素標籤在容器中的內部表示。<bean></bean>元素標籤用於class,scope,lazy-init等配置屬性,BeanDefinition則提供了相應的beanClass,scope,lazyInit類屬性,BeanDefinition就像<bean></bean>的映象。

BeanDefinition類的整合結構如下:

RootBeanDefinition是最常用的實現類,它對應一般性的<bean></bean>元素標籤。配置檔案可以定義父子bean,父bean使用RootBeanDefinition,子Bean使用ChildBeanDefinition表示,而沒有父bean就預設使用RootBeanDefinition表示。 AbstractBeanDefinition對二者共同的類資訊進行抽象。

BeanDefinition是對配置檔案中的<bean></bean>進行表示,最終將BeanDefinition會被儲存在Spring的記憶體資料庫BeanDefinitionRegistry中,後續的操作直接從這個資料庫中直接獲取,BeanDefinition只在容器啟動時載入並解析,除非容器重新整理或者重啟,這些資訊不會發生變化。

InstantiationStrategy

org.springframework.beans.factory.support.InstantiationStrategy負責根據BeanDefinition物件建立一個Besan例項。Spring之所以將例項化Ban共工作通過一個策略介面進行描述,是為了可以方便的採用不同的例項化策略,以滿足不太的應用需求,如通過CGLib類庫為Bean動態建立子類再進行例項化,InstantiationStrategy類的繼承結構如下: 1.SimpleInstantiationStrategy是最常用的例項化策略,該策略理由Bean實現類的預設建構函式,帶參建構函式或工廠方法建立Bean的例項。

2.CglibSubclassingInstantiationStrategy拓展了SimpleInstantiationStrategy,為需要進行方法注入的Bean提供了支援,然後使用這個動態生成的子類建立bean的例項。

InstantiationStrategy僅負責例項化Bean的操作,相當於執行Java語言的new操作,它只負責例項化Bean,沒有涉及任何的屬性設定,實際上得到的是一個半成品的Bean,屬性操作交給BeanWrapper

BeanWrapper

屬性的設定由BeanWrapper這個代理器完成,InstantiationStratedy創建出Bean例項之後,BeanWrapper來完成屬性填充的工作,容器主控程式將Bean例項通過BeanWrapper包裝起來,這是通過呼叫BeanWrapper#setWrappedInstance(Object obj)方阿飛完成的。BeanWrapper類的繼承結構如下:

PropertyAccessor和PropertyEditorRegistry是BeanWrapper的兩個頂級介面,PropertyAccessor定義了各種訪問Bean屬性的介面,如setPropertyValue(String,Object),setPropertyValues(PropertyValue pvs)等;而PropertyEditorRegistry是屬性編輯器的登錄檔.BeanWrapper實現類BeanWrapperImpl作用: 1.Bean包裹器 2.屬性訪問器 3.屬性編輯器登錄檔

一個BeanWrapperImpl例項內部封裝了兩類元件:1.被封裝的待處理的Bean,以及一套用於設定Bean屬性的屬性編輯器。 屬性的注入需要從BeanDefinitionRegistry中獲取到BeanDefinition,然後Spring的主控程式從BeanDefinition中獲取Bean的屬性的配置資訊PropertyValue,並且使用屬性編輯器對PropertyValue進行裝換以得到Bean的屬性值。BeanWrapper內部使用了Spring的BeanUtils工具類對Bean進行反射曹祖哦,設定屬性。

屬性編輯器

Sun所制定的JavaBean規範很大程度上是為IDE準備的——它讓IDE能夠以視覺化的方式設定avaBean的屬性,如果在IDE中開發一個視覺化的應用程式,則需要通過屬性設定的方式對組成的各種元件進行定製,IDE通過屬性屬性編輯器讓開發人員使用視覺化的方式設定元件的屬性。

IDE都支援JavaBean規範所定義的屬性編輯器,當元件開發商釋出一個元件時,它往往將元件對應的屬性編輯器捆綁發行,這樣開發者就可以在IDE環境下方便地利用屬性編輯器對元件進行定製工作。

JavaBean規範通過java.beans.PropertyEditor定義了設定JavaBean屬性地方法,通過BeanInfo描述了JavaBean描述了JavaBean的哪些屬性是可以定製的,此外描述了可定製屬性與PropertyEditor的對應關係。

BeanInfo與JavaBean之間的的對應關係通過二者之間的命名的規範確立。對應JavaBean的BeanInfo採用如下的命名規範:<Bean>BeanInfo.例如ChartBean對應的BeanInfo為ChartBeanInfo.當JavaBean連同其屬性編輯器以通註冊到IDE中後,在開發介面中對JavaBean進行定製時,IDE就會根據JavaBean規範找到對應的BeanInfo,再根據BeanInfo的描述資訊找到BeanInfo中描述西悉尼找到JavaBean屬性描述(是否開發,使用那個屬性編輯器),進而為JavaBean生成特定的開發編輯介面.

JavaBean規範提供了一個管理預設屬性編輯器的管理器PropertyEditorManager,該管理器內儲存者一些常見的型別的屬性編輯器。如果某個JavaBean的常見屬性沒有通過BeanInfo顯式地指定屬性編輯器,那麼IDE將自動使用PropertyEditorManager中註冊地對應預設地屬性編輯器。

PropertyEditor

PropertyEditor是屬性編輯器地介面,規範了將外部地設定值轉換為內部的JavaBean屬性值的轉換介面方法,PropertyEditor主要的介面方法: 1.getValue():返回屬性的當前值,基本型別被封裝成對應的封裝類例項。 2.setValue(Object value):設定屬性值,基本型別以瘋傳類傳入

3.String getAsText():將屬性物件用字串表示,以便外部的屬性編輯器能以視覺化的方式顯示。預設的返回null,表示該屬性不能以字串表示。
4.void setAsText(String text):用一個屬性去更新屬性的內部值,這個字串一般從外部屬性扁你機器傳入。
5.String[] getTags():返回不鳥事有效屬性值的字串陣列(如boolean對應的由效Tag為true和false),以便屬性編輯器能以下拉框方式顯示出來。預設返回null,表示屬性沒有匹配的字元候選值有些集合。
6.String getJavaInitializationString():為屬性提供一個表示初始值得字串,屬性編輯器以此值作為屬性得預設值。

PropertyEditor介面方法是內部屬性值和外部屬性值得溝通橋樑,是專門為IDE中得視覺化屬性編輯器提供得。

BeanInfo

BeanInfo主要描述了JavaBean的哪些屬性可以編輯對應的屬性編輯器,每個屬性對應一個屬性描述器PropertyDescriptor。建構函式public PropertyDescriptor(String propertyName, Class<?> beanClass),其中propertyName:屬性名,beanClass:javaBean對應的class。此外PropertyDescriptor還有一個方法 public void setPropertyEditorClass(Class<?> propertyEditorClass)方法,用於為JavaBean屬性指定編輯器。BeanInfo介面最重要的方法就是PropertyDescriptor[] getPropertyDescriptors(),該方法返回JavaBean的屬性描述器陣列。 BeanInfo介面的一個常用實現類是SimpleBeanInfo,一般情況下,可以通過拓張SimpleBeanInfo實現自己的功能。

Spring預設的屬性編輯器

Spring的屬性編輯器和傳統用於IDE開發的屬性編輯器不同,它沒有UI介面,僅負責將配置檔案中的檔案配置值轉換為Bean屬性的對應值,所以Spring的屬性編輯器並非傳統意義上的JavaBean屬性編輯器。 Spring為常見的屬性累提供了預設的屬性編輯器。BeanWrapperImpl類拓展了PropertyEditorRegistrySupport類,Spring在PropertyEditorRegistrySupport中為常見屬性型別提供了預設的屬性編輯器。

PropertyEditorRegistrySupport有兩個變數 Map<Class<?>, PropertyEditor> defaultEditors:用於儲存預設屬性型別的編輯器,元素的鍵為類的屬性型別,值為對應的屬性編輯器例項。 Map<Class<?>, PropertyEditor> customEditors:用於儲存使用者自定義的屬性編輯器,元素的鍵值和defaultEditors相同。 ![](htt ps://oscimg.oschina.net/oscnet/fead06d498367e6b6b83997e312b3df412b.jpg)

這些預設的屬性編輯器用於解決常見的屬性型別的是註冊問題。如果使用者的應用包括一些特殊的型別的屬性的話,而且希望配置檔案中以字面值提供配置,那麼就需要編寫自定義屬性編輯器註冊到Spring容器中。這樣,Spring才能將配置檔案中的配置屬性配置值轉換為對應的屬性型別值。

自定義屬性編輯器

Spring的帶份預設屬性編輯機器都直接拓展於java.beans.PropertyEditorSupport類,開發者也可以通過拓展PropertyEditorSupport實現自己的屬性編輯器。相對於用於IDE環境的屬性百年機器來說,Spring環境下使用的屬性編輯器的功能比較單一,僅需要將配置檔案中的字面值轉換為屬性型別的物件即可,並不需要提供UI介面,因此需要簡單覆蓋PropertyEditorSupport的setAsText()即可。

例子: 1.Boss.java

public class Boss {
private String name;
private Car car = new Car();

public Car getCar() {
	return car;
}

public void setCar(Car car) {
	this.car = car;
}

public String getName() {
	return name;
}

public void setName(String name) {
	this.name = name;
}

[@Override](https://my.oschina.net/u/1162528)
public String toString() {
	return "Boss{" +
			"name='" + name + '\'' +
			", car=" + car +
			'}';
}
}

Car.java

public class Car {
private int maxSpeed;
public String brand;
private double price;
public String getBrand() {
	return brand;
}

public void setBrand(String brand) {
	this.brand = brand;
}

public int getMaxSpeed() {
	return maxSpeed;
}

public void setMaxSpeed(int maxSpeed) {
	this.maxSpeed = maxSpeed;
}

public double getPrice() {
	return price;
}

public void setPrice(double price) {
	this.price = price;
}

public String toString(){
	return "brand:"+brand+"/maxSpeed:"+maxSpeed+"/price:"+price;
}
}

自定義屬性編輯器CustomerCarEditor.java

public class CustomerCarEditor extends PropertyEditorSupport {

	//將字面值轉換為屬性型別物件
	[@Override](https://my.oschina.net/u/1162528)
	public void setAsText(String text) throws IllegalArgumentException {
		if (StringUtils.isEmpty(text)||text.indexOf(",")==-1){
			throw new IllegalArgumentException("設定的字串格式不正確");
		}
		String[] infos = text.split(",");
		Car car = new Car();
		car.setBrand(infos[0]);
		car.setMaxSpeed(Integer.valueOf(infos[1]));
		car.setPrice(Double.valueOf(infos[2]));
		//呼叫父類得setValue()方法設定轉換後得屬性物件
		setValue(car);
	}
}

beans.xml配置檔案:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
		 http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

	<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
		<property name="customEditors">
			<map>
				<entry key="com.flexible.editor.editorbean.Car"
					   value="com.flexible.editor.editorbean.CustomerCarEditor"/>
			</map>
		</property>
	</bean>

	<bean id="boss" class="com.flexible.editor.editorbean.Boss">
		<property name="name" value="John"/>
		<property name="car" value="紅旗CA72,200,20000.00"/>
	</bean>

</beans>

測試程式碼:

    ApplicationContext context = new ClassPathXmlApplicationContext("classpath:editor/beans");
    Boss boss = (Boss) context.getBean("boss");
    System.out.println(boss.toString());

執行結果:

Boss{name='John', car=brand:紅旗CA72/maxSpeed:200/price:20000.0}

PropertyPlaceholderConfigurer屬性檔案

PropertyPlaceholderConfigurer能夠使Bean在配置時引用外部屬性檔案。PropertyPlaceholderConfigurer實現了BeanFactoryPostProcessorBean介面。

PropertyPlaceholderConfigurer屬性檔案

jdbc.properties

dbName=sampledb
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/${dbName}
#userName=root
#password=123456
userName=WnplV/ietfQ=
password=QAHlVoUc49w=

beans.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
		 http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		 http://www.springframework.org/schema/context
		 http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!--引入jdbc.properties屬性檔案-->
<bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"
p:location="classpath:placeholder/jdbc.properties"
	  p:fileEncoding="utf-8">
</bean>
<!---->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="${driverClassName}"
p:url="${url}"
p:username="${userName}"
p:password="${password}"
></bean>
</beans>

propertyPlaceholderConfigurer的其他屬性 1.locations:如果只有一個屬性檔案,直接使用location指定就可以,如果有多個屬性檔案,則可以通過locations屬性進行設定。可以像配置List一樣配置locations屬性。

2.fileEncoding:屬性檔案的編碼格式。Spring使用了作業系統預設的編碼戈斯和,如果採用了特殊的編碼格式需要通過該屬性顯式指定。

3.order:如果配置i文化你中定義了多個PropertyPlaceholderConfigurer,則通過該屬性指定有限順序

4.placeholderPrefix:在上面的例子中,可可以通過${屬性名}引用屬性檔案中的屬性項,其中"${為佔位符字首","}"是暫未付字尾

可以使用<context:property-placeholder location="classpath:placeholder/jdbc.properties"></context:property-placeholder>引入屬性檔案,但是如果需要一些高階功能(加密)

基於註解及基於Java類的配置中引用屬性

國際化資訊

為每種語言提供一套相應的資原始檔俺,並以規範化的命名的方式儲存在特定的目錄中,由系統自動根據客戶端語言選擇合適的資原始檔。"國際化資訊"也成為"本地化資訊",一般需要兩個條件才可以確定,Java通過java.util.Local類白哦是一個本地化物件,它允許通過語言引數和國家/地區引數建立以一個確定的本地化物件。 例如: public class LocalUtils {

public static Locale myLocal(){
    //帶有語言和國家/地區的本地化物件
    Locale local = new Locale("zh","CN");
    //只有語言資訊的本地化物件。
    Locale locale2 = new Locale("zh");
    //等同於Locale("zh","CN")
    Locale locale3 = Locale.CHINA;
    //等同於Locale("zh")
    Locale locale4 = Locale.CHINESE;
    //獲取本地系統預設的本地化物件
    Locale locale5 = Locale.getDefault();
    return locale5;
}
}

注意: 在測試的時候如果需要該百年系統預設的本地化設定,則可以在啟動JVM時通過命令參實指定:java -Duser.language=en -Duser.region=US MyTest

本地化工具

NumberFormart,DateFormart,MessageFormat。MessageFormat在NumberFormart和DateFormat的基礎之上提供了佔位符字串的格式換的功能,支援時間,貨幣,陣列以及物件屬性格式化操作。

例如: Locale locale = new Locale("zh","CN"); NumberFormat format = NumberFormat.getCurrencyInstance(locale); double num = 123456.78; System.out.println(format.format(num));

    //格式化資訊串
    String pattern1 = "{0},你好!你於{1}我行存入了{2}元";
    //用於動態替換佔位符的引數
    Object[] params = {"張三",new GregorianCalendar().getTime(),1000000.0E3};
    //使用預設的本地化物件格式化資訊
    String message1 = MessageFormat.format(pattern1,params);
    System.out.println(message1);

    String pattern2 = "At {1,time,short} On {1,date,long},{0} paid {2,number,currency}.";
    MessageFormat messageFormat = new MessageFormat(pattern2,Locale.US);
    String result = messageFormat.format(params);
    System.out.println(result);

執行結果: CN ¥123,456.78 張三,你好!你於18-11-19 下午12:51我行存入了1,000,000,000元 At 12:51 PM On November 19, 2018,張三 paid $1,000,000,000.00.

ResourceBundle 如果需要國際化的支援,就必須為不同的本地化型別非被提供對應的資原始檔,並以鍋飯的方式進行命名: <資源名><語言程式碼><國家/地區程式碼>.properties,其語言程式碼和讀取程式碼都是可選的。<資源名>.properties命名的國際化資原始檔是預設的資原始檔,即某個本地換化型別在系統找不到的對應的資原始檔,就才有這個預設的資原始檔。 例如:

    Locale locale = new Locale("zh","CN");
    Locale locale2 = new Locale("en","US");
    ResourceBundle resourceBundle = ResourceBundle.getBundle("com/flexible/message",locale);
    ResourceBundle resourceBundle2 = ResourceBundle.getBundle("com/flexible/message",locale2);
    System.out.println(resourceBundle.getString("userName"));
    System.out.println(resourceBundle2.getString("userName"));

執行結果: 張三 zhangsan

MessageSource

Spring定義了訪問國際化資訊的MessageSource介面,並且提供了若干個易用的實現類,這些重要的方法如下:

1.String getMessage(String code, Object[] args, String defaultMessage, Locale locale):code表示國際化資訊中的屬性名稱,args用於傳遞格式化串佔位符所用的執行期引數;當在資源中找不到對應的屬性名稱時,返回defaultMessage引數指定的預設資訊,locale表示本地化物件。

2.String getMessage(String code, Object[] args, Locale locale)throws NoSuchMessageException:與1的方法一樣,只是在找不到資源的時候丟擲NoSuchMessageException

3.String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException:將屬性名,引數陣列以及預設資訊封裝起來,他的功能和第一個介面方法相同。

MessageSource的類結構

HierarchicalMessageSource:介面添加了兩個方法,建立了父子層級的MessageSource結構,類似於前面介紹的HierachicalBeanFactory.該介面的setParentMessageSource(MessageSource parent)放啊用於設定父MessageSource和MessageSource getParentMessageSource()返回父MessageSource

ResourceBundleMessageSource和ReloadableResourceBundleMessageSource是HierarchicalMessageSource兩個重要的子類。

ResourceBundleMessageSource

允許使用者通過beanName制定一個字眼名(包括類路徑的全限定資源名),或者通過beanNames指定一組資源名。使用ResourceBundleMessageSource例子如下:

		String[] configs = {"message/beans"};
		ApplicationContext context = new ClassPathXmlApplicationContext(configs);
		//獲取MessageSource的Bean
		MessageSource ms = (MessageSource)context.getBean("mySource");
		Object[] params = {"jack",new GregorianCalendar().getTime()};
		//獲取格式化的國際資訊
		String str1 = ms.getMessage("userName",params, Locale.US);
		System.out.println(str1);

xml配置檔案:

<bean id="mySource" class="org.springframework.context.support.ResourceBundleMessageSource">
	<property name="basenames">
		<list>
			<value>com/flexible/message</value>
		</list>
	</property>
</bean>

執行結果: zhangsan

ReloadableResourceBundleMessageSource

該類可以是實現資源的定時重新整理

<bean id="mySource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
	<property name="basenames">
		<list>
			<value>com/flexible/message</value>
		</list>
	</property>
	<property name="cacheSeconds" value="5"></property>
</bean>

容器級的國際化資訊資源

Spring正常情況下時不會將國際化資源作為Bean注入其他的Bean當中,而是做為容器的基礎設施向所有的bean開放。在前面已經介紹過initMessageSource()就是初始化容器中的國際化資訊資源,它根據反射機制從BeanDefinitionRegistry中找出名為messageSource且型別為org.springframework.context.MessageSource的Bean,將這個Bean定義的資訊資源載入為容器級別的國際化資訊資源。 例如:

		ApplicationContext context = new ClassPathXmlApplicationContext("containermessagesouece/beans");
		String userName1 = context.getMessage("userName", params, Locale.CHINA);
		String userName2 = context.getMessage("userName", params, Locale.US);
		System.out.println("userName1:"+userName1+"---"+"userName2:"+userName2);

beans.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
		 http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		 http://www.springframework.org/schema/context
		 http://www.springframework.org/schema/context/spring-context-4.0.xsd">


//這個地方只能命名為messageSource,否則就會丟擲NoSuchMessageException
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
	<property name="basenames">
		<list>
			<value>com/flexible/message</value>
		</list>
	</property>
</bean>
</beans>

容器事件