Spring学习系列(四)——Spring中的国际化
1.Java中的国际化
国际化(Internationalization)简称 i18n,简单来说就是不同国家/地区/语言的用户,访问同一个程序,得到对应的本地化资源。
首先要确定国家/地区/语言(Locale类)
然后根据不同的Locale获取对应的本地化资源(locale敏感的)。
而本地化资源相关的主要有两种:ResourceBundle和Format抽象类的子类。
①Jdk为ResourceBundle抽象类提供了两个子类(ListResourceBundle和PropertyResourceBundle)
当然也可以参考ResourceBundle编写自定义的子类MyResources和XMLResourceBundle等(源码注释部分)。
(FORMAT_DEFAULT默认使用java.class和java.properties两种格式)其中properties的命名规则basename_language_country.properties。
②Format,相对简单不再过多描述。
Format子类中关于Local的使用。
2.Spring中的国际化
首先说明Spring中国际化的支持是AbstractApplicationContext中定义的默认bean(ApplicationContext实现了MessageSource接口), private MessageSource messageSource;
而在基于Spring的Web应用中使用我们更多关注的是如何确定Local的问题,而对资源的获取则更多的是基于配置。
①通过LocaleResolver获取Local
- 读取客户端浏览器的默认语言,根据Request Headers中的Accept-language来判断。
- 客户端传参,并基于Session和Cookie的对Local进行管理(例如一些网站的语言切换选项)。
使用RequestContextUtils.getLocale(request)获取Local;
参考DispatcherServlet的initLocaleResolver()方法,在bean中配置不同的LocaleResolver实现
②通过MessageSource获取ResoureBundle
- 对与一些简单的资源,我们可以采用properties中配置
- 在Web应用中,如果资源文件过多,使用properties维护将是个麻烦,可以采用数据库存储结合缓存技术实现。
③messageResoure的配置
核心是AbstractApplicationContext中initMessageSource()中涉及的HierarchicalMessageSource接口;
由AbstractBeanFactory中的containsLocalBean(String name)区分为两类:使用配置的HierarchicalMessageSource实现和DelegatingMessageSource(HierarchicalMessageSource的简单实现)
而在messageSource配置class时,有两个常用的HierarchicalMessageSource实现可供选择:ResourceBundleMessageSource和ReloadableResourceBundleMessageSource
两者都是利用资源名通过getMessage()接口就可以加载整套的国际化资源文件,唯一区别在于ReloadableResourceBundleMessageSource可以定时刷新资源文件,以便在应用程序不重启的情况下感知资源文件的变化。很多生产系统都需要长时间持续运行,系统重启会给运行带来很大的负面影响,这时通过该实现类就可以解决国际化信息更新的问题。上面的配置中cacheSeconds属性让ReloadableResourceBundleMessageSource每5秒钟刷新一次资源文件(在真实的应用中,刷新周期不能太短,否则频繁的刷新将带来性能上的负面影响,一般不建议小于30分钟)。cacheSeconds默认值为-1表示永不刷新,此时,该实现类的功能就蜕化为ResourceBundleMessageSource的功能。
④简单的代码示例
a.在spring配置文件中定义messageSource<bean>
b.定义不同Local的properties文件,命名规则basename_language_country.properties和java中的一致。
c.代码
ApplicationContext applicationContext=new FileSystemXmlApplicationContext("classpath:spring-config.xml"); String message=applicationContext.getMessage("HelloWorld",new Object[]{"hello",new Date()}, Locale.CHINA);
小结:可以看出使用spring的国际化更加灵活(ReloadableResourceBundleMessageSource的动态读取),基于MessageFormat的参数化列表,以及中文支持可以设置编码格式(java中处理相对麻烦)。
3.总结
Java中:重点了解ResoureBundle的使用参考源码解析图。
Spring中:重点分两部分,①通过LocaleResolver获取Local,②通过通过MessageSource获取ResoureBundle
Spring的国际化是基于Java(Jdk)国际化的扩展,在Web项目中使用更加灵活。
阅读Java(其实这里使用Jdk更合适)源码还能够捋清思路,Spring源码阅读着有些吃力,目前阶段只能结合一些博客挑重点部分的源码进行解读了。
4.参考资料