1. 程式人生 > >spring 如何動態載入properties檔案

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有兩個常用的實現ReloadableResourceBundleMesssageSourceResourceBundleMessageSource.

  • 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查詢資源的區別:

  1. ResourceBundleMessageSource在XML配置中無法指定編碼,而ReloadableResourceBundleMessageSource可以指定編碼

  2. 載入資原始檔的方式不同:

    1. 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預設的載入方式,先從當前執行緒中獲取類載入器,如果沒有,就獲取這個類本身的類載入器

    1. 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);
        }
    }
    
    1. 小結:ResourceBundleMessageSource從classloader中載入資原始檔,可以看到:ReloadableResourceBundleMessageSource載入時,預設使用DefaultResourceLoader,他會先判斷資源path是否帶有classpath:字首,如果有,用 ClassPathResource去載入資原始檔,如果沒有試著用檔案協議的url去訪問,再沒有就在contextPath即WEB-INF下查詢.
  3. 在專案中,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> 
  1. 我們可以在MessageSourceHelper中加入自己的業務,注入依賴後,就可以在其他類中呼叫MessageSourceHelper中的方法。

  2. 理論簡要: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會用得更多一些