Spring3.1.0实现原理分析(二).国际化(i18n)

        今天和大家一起分析下Spring国际化模块的结构。什么是国际化呢? 我想引用李刚老师曾说过的一句话:“所谓国际化其实就是字符串的查找和替换过程”。查找就是根据code去资源文件中获取value,替换就是把value中可能包含的占位符替换成实际值,所以国际化的关键在于资源文件的加载和消息的渲染。

     照例先上一张图,下图是Spring国际化模块主要接口(类)的结构图。

Spring3.1.0实现原理分析(二).国际化(i18n)_第1张图片

-------------------------------------------------------华丽的分隔线---------------------------------------------------

下面我们来具体分析下上图中的每个接口(类)的作用。

1.  消息源接口 (MessageSource)

     这个接口定义了国际化最核心的功能“获取消息”。一共定义了三个重载的用于获取消息的方法,方法最多可以获得“编码”、“实参数组”、“默认消息”、“本地化对象”四个参数。ApplicationContext之所以具备国际化的能力,其实就是实现了这个接口,通过getMessage(...)方法获取消息。

2. 分层消息源接口 (HierarchicalMessageSource) 

     这个接口定义了两个方法,分别是获取父消息源和设置父消息源,所以实现了该接口的类具备访问父消息源的功能。

3.  抽象消息源支持类(MessageSourceSupport) 

      这是一个抽象类,这意味着它不能独立存在,抽象类通常更像是一个模板,它为所有的派生类定义了公用的功能。这个类最主要的作用是提供了渲染默认消息的功能 , 首先它会创建消息格式化对象MessageFormat(java系统类),并且会把用过的格式化对象缓存起来。什么时候需要使用默认消息呢? 当然是根据code在资源文件中找不到value的时候使用了。

4.  代理消息源对象(DelegatingMessageSource) 

      就跟这个类的名称一样“代理”,它首先会把获取消息的任务委托给父消息源对象来处理,如果父消息源对象为null呢? 它会判断是否有提供默认消息,如果有的话就会调用“它爸爸”的方法,对默认消息执行格式化操作。

5. 抽象消息源类(AbstractMessageSource)

    这个类从上面的图中可以很直观的感受到这是一个中枢类,确实这个类很重要,它实现了获取消息的主体逻辑,下面我来具体描述下获取消息的处理过程,

  1. 根据编码和本地化对象获取消息格式化对象(抽象方法), 然后调用其格式化方法渲染消息。
  2. 如果未能成功获取消息格式化对象,则委托给父消息源对象.
  3. 如果父消息源为null或者父消息源也未能成功获取消息,并且默认消息不为null, 则调用超类方法渲染消息.
  4. 如果默认消息为null, 则判断是否把code作为消息返回还是抛出异常,这个行为由成员变量useCodeAsDefaultMessage来控制,其默认值是false,  所以会抛出异常。

      上面的第一个步骤是获取消息格式化对象,并且被定义成抽象方法,说明需要派生类实现,方法的传入参数是code和本地化对象,我们查一下java的api看下MessageFormat类构造函数的定义。

Spring3.1.0实现原理分析(二).国际化(i18n)_第2张图片

        无论哪个构造函数,都需要传入消息(可能包含占位符),那么消息从哪里来呢? 是从用户配置的国际化资源文件根据code获取的。既然派生类要实现获取消息格式化对象的抽象方法,那就说明派生类首先要实现加载国际化资源文件的功能。Spring是怎么加载国际化资源文件的呢? 请接着往下看。

6. ResourceBundle消息源类 (ResourceBundleMessageSource)

     该类通过jdk系统类ResourceBundle加载国际化资源文件, 由于ResourceBundle不支持重新, 所以这个实现类不具备重加载的功能。这个类会缓存获取的ResourceBundle对象和创建的MessageFormat对象。

7. 可重加载消息源类(ReloadableResourceBundleMessageSource)

     这个类我个人觉得是Spring国际化模块中最有意思的类,因为它支持国际化资源文件的重加载。之所以支持重加载,是因为它并非使用java系统类ResourceBundle实现资源加载,Spring自己定义了一个接口“PropertiesPersister”, 用于实现把国际化资源文件加载到属性集对象, 支持properties和xml两种格式的资源文件。

    重加载的行为是通过成员变量cacheMillis来控制的,这个值的单位在Spring内部是毫秒,但是用户配置的时候是秒,比如你希望刷新周期是10秒,就填10。cacheMillis值和重加载行为对应关系如下,

  • 默认-1,不执行重加载。
  • 如果值是正数,当获取消息时,会判断指定周期是否到达,如果到达再检测资源文件最后修改时间戳,如果资源文件被修改了则重加载。
  • 如果值是零,当获取消息时,只检测资源文件最后修改时间戳,如果资源文件被修改了则重加载。

 

    好了,Spring国际化模块架构就分析到这里了,最后再总结下,其实国际化涉及的主要功能点无非是加载资源文件和渲染消息。

转载于:https://my.oschina.net/u/157224/blog/871973

你可能感兴趣的:(Spring3.1.0实现原理分析(二).国际化(i18n))