返回介绍

6.6.3 初始化消息资源

发布于 2025-04-22 22:09:13 字数 5942 浏览 0 评论 0 收藏

在进行这段函数的解析之前,我们同样先来回顾 Spring 国际化的使用方法。

假设我们正在开发一个支持多国语言的 Web 应用程序,要求系统能够根据客户端的系统的语言类型返回对应的界面:英文的操作系统返回英文界面,而中文的操作系统则返回中文界面——这便是典型的 i18n 国际化问题。对于有国际化要求的应用系统,我们不能简单地采用硬编码的方式编写用户界面信息、报错信息等内容,而必须为这些需要国际化的信息进行特殊处理。简单来说,就是为每种语言提供一套相应的资源文件,并以规范化命名的方式保存在特定的目录中,由系统自动根据客户端语言选择适合的资源文件。

“国际化信息”也称为“本地化信息”,一般需要两个条件才可以确定一个特定类型的本地化信息,它们分别是“语言类型”和“国家/地区的类型”。如中文本地化信息既有中国大陆地区的中文,又有中国台湾地区、中国香港地区的中文,还有新加坡地区的中文。Java 通过 java.util.Locale 类表示一个本地化对象,它允许通过语言参数和国家/地区参数创建一个确定的本地化对象。

java.util.Locale 是表示语言和国家/地区信息的本地化类,它是创建国际化应用的基础。下面给出几个创建本地化对象的示例:

//① 带有语言和国家/地区信息的本地化对象

Locale locale1 = new Locale("zh","CN");

//② 只有语言信息的本地化对象

Locale locale2 = new Locale("zh");

//③ 等同于 Locale("zh","CN")

Locale locale3 = Locale.CHINA;

//④ 等同于 Locale("zh")

Locale locale4 = Locale.CHINESE;

//⑤ 获取本地系统默认的本地化对象

Locale locale 5= Locale.getDefault();

JDK 的 java.util 包中提供了几个支持本地化的格式化操作工具类:NumberFormat、DateFormat、MessageFormat,而在 Spring 中的国际化资源操作也无非是对于这些类的封装操作,我们仅仅介绍下 MessageFormat 的用法以帮助大家回顾:

 //①信息格式化串

String pattern1 = "{0},你好!你于{1}在工商银行存入{2} 元。";

String pattern2 = "At {1,time,short} On{1,date,long},{0} paid {2,number, currency}.";

//②用于动态替换占位符的参数

Object[] params = {"John", new GregorianCalendar().getTime(),1.0E3};

//③使用默认本地化对象格式化信息

String msg1 = MessageFormat.format(pattern1,params);

//④使用指定的本地化对象格式化信息

MessageFormat mf = new MessageFormat(pattern2,Locale.US);

String msg2 = mf.format(params);

System.out.println(msg1);

System.out.println(msg2);

Spring 定义了访问国际化信息的 MessageSource 接口,并提供了几个易用的实现类。MessageSource 分别被 HierarchicalMessageSource 和 ApplicationContext 接口扩展,这里我们主要看一下 HierarchicalMessageSource 接口的几个实现类,如图 6-3 所示。

figure_0167_0035

图 6-3 MessageSource 类图结构

HierarchicalMessageSource 接口最重要的两个实现类是 ResourceBundleMessageSource 和 ReloadableResourceBundleMessageSource。它们基于 Java 的 ResourceBundle 基础类实现,允许仅通过资源名加载国际化资源。ReloadableResourceBundleMessageSource 提供了定时刷新功能,允许在不重启系统的情况下,更新资源的信息。StaticMessageSource 主要用于程序测试,它允许通过编程的方式提供国际化信息。而 DelegatingMessageSource 是为方便操作父 MessageSource 而提供的代理类。仅仅举例 ResourceBundleMessageSource 的实现方式。

(1)定义资源文件。

messages.properties(默认:英文),内容仅一句,如下:

test=test

messages_zh_CN.properties(简体中文):

test=测试

然后 cmd,打开命令行窗口,输入 native2ascii -encoding gbk C:\messages_zh_CN.properties C:\messages_zh_CN_tem.properties ,并将 C:\messages_zh_CN_tem.properties 中的内容替换到 messages_zh_CN.properties 中,这样 messages_zh_CN.properties 文件就存放的是转码后的内容了,比较简单。

(2)定义配置文件。

<bean id="messageSource" class="org.Springframework.context.support.ResourceBundleMessageSource">

  <property name="basenames">

  <list>

   <value>test/messages</value>

  </list>

 </property>

</bean>

其中,这个 Bean 的 ID 必须命名为 messageSource,否则会抛出 NoSuchMessageException 异常。

(3)使用。通过 ApplicationContext 访问国际化信息。

String[] configs = {"applicationContext.xml"};

ApplicationContext ctx = new ClassPathXmlApplicationContext(configs);

//①直接通过容器访问国际化信息

Object[] params = {"John", new GregorianCalendar().getTime()};

String str1 = ctx.getMessage("test",params,Locale.US);

String str2 = ctx.getMessage("test",params,Locale.CHINA);

System.out.println(str1);

System.out.println(str2);

了解了 Spring 国际化的使用后便可以进行源码的分析了。

在 initMessageSource 中的方法主要功能是提取配置中定义的 messageSource,并将其记录在 Spring 的容器中,也就是 AbstractApplicationContext 中。当然,如果用户未设置资源文件的话,Spring 中也提供了默认的配置 DelegatingMessageSource。

在 initMessageSource 中获取自定义资源文件的方式为 beanFactory.getBean(MESSAGE_ SOURCE_BEAN_NAME, MessageSource.class),在这里 Spring 使用了硬编码的方式硬性规定了子定义资源文件必须为 message,否则便会获取不到自定义资源配置,这也是为什么之前提到 Bean 的 id 如果部位 message 会抛出异常。

protected void initMessageSource() {

  ConfigurableListableBeanFactory beanFactory = getBeanFactory();

  if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {

  //如果在配置中已经配置了 messageSource ,那么将 messageSource 提取并记录在

  this.messageSource 中

   this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.

  class);

   // Make MessageSource aware of parent MessageSource.

   if (this.parent != null && this.messageSource instanceof Hierarchical

   MessageSource) {

    HierarchicalMessageSource hms = (HierarchicalMessageSource) this.

   messageSource;

    if (hms.getParentMessageSource() == null) {

    hms.setParentMessageSource(getInternalParentMessageSource());

   }

  }

   if (logger.isDebugEnabled()) {

    logger.debug("Using MessageSource [" + this.messageSource + "]");

  }

  }else {

  //如果用户并没有定义配置文件,那么使用临时的 DelegatingMessageSource 以便于作为调用

  getMessage 方法的返回。

   DelegatingMessageSource dms = new DelegatingMessageSource();

  dms.setParentMessageSource(getInternalParentMessageSource());

   this.messageSource = dms;

  beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME,

  this.messageSource);

   if (logger.isDebugEnabled()) {

    logger.debug("Unable to locate MessageSource with name '" +

    MESSAGE_SOURCE_BEAN_NAME +

    "': using default [" + this.messageSource + "]");

  }

 }

}

通过读取并将自定义资源文件配置记录在容器中,那么就可以在获取资源文件的时候直接使用了,例如,在 AbstractApplicationContext 中的获取资源文件属性的方法:

public String getMessage(String code, Object args[], Locale locale) throws NoSuchMessage

Exception {

  return getMessageSource().getMessage(code, args, locale);

}

其中的 getMessageSource() 方法正是获取了之前定义的自定义资源配置。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。