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会用得更多一些

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容