说说在 Spring 中如何国际化信息

字数 761阅读 771

1 MessageSource

Spring 定义了 MessageSource 接口,用于访问国际化信息。

  • getMessage(String code, Object[] args, String defaultMessage, Locale locale)
  • getMessage(String code, Object[] args, Locale locale)
  • getMessage(MessageSourceResolvable resolvable, Locale locale)
属性 说明
code 国际化资源中的属性名。
args 传递格式化串占位符所用的运行期参数,当在资源找不到对应属性名时,会返回 defaultMessage 参数所指定的默认信息。
locale 表示本地化对象。
resolvable 封装了属性名、参数数组以及默认信息的大类。

1.1 类结构

HierarchicalMessageSource 接口添加了两个方法,建立了父子层级的 MessageSource 结构:

方法 说明
void setParentMessageSource(MessageSource parent) 设置父 MessageSource。
MessageSource getParentMessageSource() 获取父 MessageSource。

HierarchicalMessageSource 接口三个实现类,它们都是基于 Java 的 ResourceBundle 类实现的,允许仅通过资源名就可以加载国际化资源 。

描述
ReloadableResourceBundleMessageSource 提供了定时刷新功能,允许在不重启系统的情况下,更新资源信息 。
StaticMessageSource 主要用于程序测试,它允许通过编程的方式来提供国际化信息 。
DelegatingMessageSource 是为了方便操作父 MessageSource 而提供的代理类 。

1.2 ResourceBundleMessageSource 类

这个类允许用户通过 beanName 来指定一个资源名(包含类路径的全限定资源名),或通过 beanNames 指定一组资源名。

配置:

<?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 id="customResource"
          class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>i18n/params</value>
            </list>
        </property>
    </bean>

</beans>

测试代码:

MessageSource messageSource = (org.springframework.context.MessageSource) context.getBean("customResource");
Object[] params = {"Jack", new GregorianCalendar().getTime()};
System.out.println("中国:" + messageSource.getMessage("index.greeting", params, Locale
        .CHINA));
System.out.println("美国:" + messageSource.getMessage("index.greeting", params, Locale
        .US));

输出结果:

中国:欢迎您 Jack,现在时间 18-5-27 下午2:38
美国:Welcome Jack,current time is 5/27/18 2:38 PM

通过 Spring 我们无须再像 Java 那样,需要分别加载不同语言 、不同国家 / 地区的本地化资源文件,只需通过资源名就可以加载整套的国际化资源文件啦是不是很简单呀 O(∩_∩)O哈哈~

1.3 ReloadableResourceBundleMessageSource 类

这个类可以定时刷新资源文件,这样应用程序可以不重启的情况下感知资源文件的变化 。 很多在线系统都需要长时间地持续运行,这时如果重启系统,就会给运行带来很大的负面影响 。 这时,通过这个类就可以解决国际化信息的更新问题。

<!-- 配置资源(定时刷新)-->
<bean id="reloadedResource"
      class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basenames">
        <list>
            <value>i18n/params</value>
        </list>
    </property>
    <!-- 刷新周期,单位:s-->
    <property name="cacheSeconds" value="60"/>
</bean>

cacheSeconds 属性可以让 ReloadableResourceBundleMessageSource 每 60 秒钟刷新一次资源文件(在真实的应用中,刷新周期不能太短,否则频繁的刷新将带来性能上的负面影响,一般建议大于 30 分钟) 。cacheSeconds 默认值为 -1 表示永不刷新。

2 容器级的国际化信息资源

ApplicationContext 实现了 MessageSource 接口,所以 ApplicationContext 的实现类本身也是 MessageSource 对象。

在一般情况下,国际化信息资源应该是容器级。 MessageSource 作为容器的基础设施向容器中所有的 Bean 开放 。 国际化信息一般在系统输出信息时使用,如 Spring MVC 的页面标签,控制器 Controller 等场景,不同的模块都可能通过这些组件访问国际化信息,因此 Spring 就将国际化消息作为容器的公共基础设施对所有组件开放啦。

Spring 的 initMessageSource() 会根据反射机制从 BeanDefinitionRegistry 中找出名称为 messageSource 且类型为 org.springframework.context.MessageSource 的 Bean ,将这个 Bean 定义的信息资源加载为容器级的国际化信息资源。

<!-- 配置资源(容器级)-->
<bean id="messageSource"
      class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames">
        <list>
            <value>i18n/params</value>
        </list>
    </property>
</bean>

注意:容器级的 Bean 名约定为 “messageSource” ,否则会抛出 NoSuchMessageException 异常。

单元测试:

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Object[] params = {"Jack", new GregorianCalendar().getTime()};
System.out.println("中国:" + context.getMessage("index.greeting", params, Locale
        .CHINA));
System.out.println("美国:" + context.getMessage("index.greeting", params, Locale
        .US));

注意:这里是直接调用 ApplicationContext 的 getMessage() 来获取国际化信息的,不需要在实例化 MessageSource 对象啦 O(∩_∩)O哈哈~

推荐阅读更多精彩内容