spring 如何動態載入properties檔案
1. 在xml中配置properties路徑
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basenames"> <list> <!-- 指定資原始檔基名稱 jdbc為檔名,不包含副檔名 --> <value>classpath:resource/jdbc</value> </list> </property> </bean>
2. 獲取WebApplicationContext(需要入參HttpServerletRequest request)
ServletContext servletContext = request.getSession() .getServletContext();
WebApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(servletContext);
3. tongguo WebApplicationContext獲取中鍵值String msg = ctx.getMessage("jdbc.url",null,Locale.CHINA);
Spring的MessageSource有兩個常用的實現ReloadableResourceBundleMesssageSource和ResourceBundleMessageSource.
- ResourceBundleMessageSource:
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="parentMessageSource" ref="bizMessageSource" /> <property name = "basenames"> <list> <value>resources.cls-web-resources</value> <value>resources.cls-web-resources-definitions</value> <value>resources.cls-web-resources-menu</value> </list> </property> </bean>
- ReloadableResourceBundleMesssageSource
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="parentMessageSource" ref="bizMessageSource"/>
<property name="fallbackToSystemLocale">
<value>false</value>
</property>
<property name="basenames">
<list>
<value>classpath:resources/cls-web-resources</value>
<value>classpath:resources/cls-web-resources-definitions</value>
<value>classpath:resources/cls-web-resources-menu</value>
</list>
</property>
</bean>
原因:因為ReloadableResourceBundleMessageSource的內部使用DefaultResourceLoader來裝載ResourceBundle, 而ResourceBundleMessageSource內部是直接使用java.util.ResourceBundle.getBundle(String baseName,Locale locale, ClassLoader loader) 來獲取i18n檔案資訊,而ResourceBundle是使用"."來作為basename分隔符的
另外如果不設定"fallbackToSystemLocale"的話, 那麼當傳入的Locale是null或者ResourceBundle沒有改Locale的配置檔案的話, 那麼會返回Locale.getDefault()的Locale下的Meseage. 該設定預設為True, 也就是說, 如果找不到相應的ResourceBundle, 系統始終會顯示為中文的Resource, 建議關閉該設定, 否則fallBackLocale就沒有什麼意義了.
另外還有一個有用的設定“useCodeAsDefaultMessage”,預設為false,這樣當Spring在ResourceBundle中找不到messageKey的話,就丟擲NoSuchMessageException,把它設定為True,則找不到不會丟擲異常,而是使用messageKey作為返回值。
spring中ResourceBundleMessageSource與ReloadableResourceBundleMessageSource查詢資源的區別:
ResourceBundleMessageSource在XML配置中無法指定編碼,而ReloadableResourceBundleMessageSource可以指定編碼
載入資原始檔的方式不同:
- ResourceBundleMessageSource的載入,使用ClassUtils.getDefaultClassLoader()載入器,getDefaultClassLoader的方法程式碼如下:
public static ClassLoader getDefaultClassLoader() { ClassLoader cl = null; try { cl = Thread.currentThread().getContextClassLoader(); }catch (Throwable ex) { logger.debug("Cannot access thread context ClassLoader - falling back to system class loader", ex); } if (cl == null){ cl = ClassUtils.class.getClassLoader(); } return cl; }
這種方式也是JVM預設的載入方式,先從當前執行緒中獲取類載入器,如果沒有,就獲取這個類本身的類載入器
- ReloadableResourceBundleMessageSource預設也使用ClassUtils.getDefaultClassLoader()載入器,它載入資源的方式如下:
public Resource getResource(String location){ Assert.notNull(location, "Location must not be null"); if (location.startsWith("classpath:")) { return new ClassPathResource(location.s string("classpath:".length()), getClassLoader()); } try{ URL url = new URL(location); return new UrlResource(url); }catch (MalformedURLException ex){ return getResourceByPath(location); } }
- 小結:ResourceBundleMessageSource從classloader中載入資原始檔,可以看到:ReloadableResourceBundleMessageSource載入時,預設使用DefaultResourceLoader,他會先判斷資源path是否帶有classpath:字首,如果有,用 ClassPathResource去載入資原始檔,如果沒有試著用檔案協議的url去訪問,再沒有就在contextPath即WEB-INF下查詢.
在專案中,MessageSource不會單獨使用,通常我們會把它和自己的業務一起使用,這時候我們可以直接用它本身的方法,我們也可以在其中加入我們自己的邏輯:如,自定義的一個訊息類:
public class MessageSourceHelper {
private ResourceBundleMessageSource messageSource;
public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
String msg = messageSource.getMessage(code, args, defaultMessage, locale);
return msg != null ? msg.trim() : msg;
}
public void setMessageSource(ResourceBundleMessageSource messageSource) {
this.messageSource = messageSource;
}
}
在beans-message.xml中注入:
<bean id="messageSourceHelper" class="com.myspring.message.MessageSourceHelper">
<property name="messageSource">
<ref local="messageSource" />
</property>
</bean>
我們可以在MessageSourceHelper中加入自己的業務,注入依賴後,就可以在其他類中呼叫MessageSourceHelper中的方法。
理論簡要:ApplicationContext介面擴充套件了MessageSource 介面,因而提供了訊息處理的功能(i18n或者國際化)。與HierarchicalMessageSource一起使用,它還能夠處理巢狀的訊息,這些是Spring提供的處理訊息的基本介面。讓我們快速瀏覽一下它所定義的方法:
- String getMessage(String code, Object[] args, String default, Locale loc):用來從MessageSource獲取訊息的基本方法。如果在指定的locale中沒有找到訊息,則使用預設的訊息。args中的引數將使用標準類庫中的MessageFormat來作訊息中替換值。
- String getMessage(String code, Object[] args, Locale loc):本質上和上一個方法相同,其區別在:沒有指定預設值,如果沒找到訊息,會丟擲一個NoSuhMessageException異常。
- String getMessage(MessageSourceResolvable resolvable, Locale locale):上面方法中所使用的屬性都封裝到一個MessageSourceResolvable實現中,而本方法可以指定 MessageSourceResolvable實現。
當一個ApplicationContext被載入時,它會自動在context中查詢已定義為MessageSource型別的bean。此bean的名稱須為messageSource。如果找到,那麼所有對上述方法的呼叫將被委託給該 bean。否則ApplicationContext會在其父類中查詢是否含有同名的bean。如果有,就把它作為MessageSource。如果它最終沒有找到任何的訊息源,一個空的StaticMessageSource將會被例項化,使它能夠接受上述方法的呼叫。
Spring目前提供了兩個MessageSource的實現:ResourceBundleMessageSource和StaticMessageSource。它們都繼承 NestingMessageSource以便能夠處理巢狀的訊息。StaticMessageSource很少被使用,但能以程式設計的方式向訊息源新增訊息。ResourceBundleMessageSource會用得更多一些