ResourceBundle

Java 提供了ResourceBundle类,能够实现特定区域(语言环境)的资源加载。以便咱们在编码时能够应用一个ResourceBundle而不必思考特定的语言环境信息,程序主动通过以后的用户的语言环境信息来加载特定资源。
ResourceBundle的应用比较简单,如上面的代码。

public class ResourceBundleDemo {    public static void main(String[] args) throws UnsupportedEncodingException {        ResourceBundle rb = ResourceBundle.getBundle("test");        System.out.println(rb.getString("key1"));        rb = ResourceBundle.getBundle("test", Locale.GERMAN);        System.out.println(rb.getString("key1"));    }}

ResourceBundle通过了getBundle 工厂办法创立的实例默认被缓存。如果ResourceBundle被缓存屡次调用getBundle 办法返回同一个实例。getBundle 的客户端能够革除缓存、治理缓存的缓存工夫。参考:clearCache办法、ResourceBundle.Control.getTimeToLive和ResourceBundle.Control.needsReload。

Java平台提供了ResourceBundle两个子类ListResourceBundle 和PropertyResourceBundle。

ResourceBundle工厂办法在加载资源的过程中须要ResourceBundle.Control提供必须要的信息。ResourceBundle.Control 提供包含:bundle名字、创立Bundle、资源寻找等信息。默认的ResourceBundle.Control 能够被笼罩。默认的ResourceBundle.Control实现了两种格局资源的加载,class 格局和properties 格局。例如上面的代码:

ResourceBundle  rb = ResourceBundle.getBundle(“MyResource”); 

那么会加载MyResource.class(及相干语言区域后缀的class),如果class找不到,会加载MyResource.properties(及相干语言区域后缀的properties)的相干文件(通过PropertyResourceBundle)。

MessageFomat

MessageFormat 提供了以与语言无关形式生成连贯音讯的形式。应用此办法结构向终端用户显示的音讯。MessageFormat 自身不实现特定于语言环境的行为。特定于语言环境的行为是由所提供的模式和用于已插入参数的子格局来定义的。
MessageFormat 简略实例如下代码:

 int planet = 7; String event = "a disturbance in the Force"; String result = MessageFormat.format(     "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",     planet, new Date(), event);

MessageFormat具体应用以及pattern模式能够参考javadoc。
MessageFormat能够和ResourceBundle配合做到个不同语言环境的用户显示。

public static void main(String[] args) {    Date d = new Date();    MessageFormat format = new MessageFormat("明天是{0,date ,yyyy-MM-dd}");    System.out.println(format.format(new Object[]{d}));    format.applyPattern("today is {0,date, dd/MM/yy}");    System.out.println(format.format(new Object[]{d}));}

Spring MessageSource

Spring MessageSource接口,用来反对参数化和国际化音讯。

public interface MessageSource {    @Nullable    String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);    String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;    String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;}

Spring 提供了两个开箱即用的MessageSource实现,ResourceBundleMessageSource 和ReloadableResourceBundleMessageSource。

在AbstractApplicationContext中的initMessageSource办法,检测有无配置名称为MESSAGE_SOURCE_BEAN_NAME(messageSource)的bean,如果没有配置则生成一个DelegatingMessageSource 进行注册。initMessageSource的源码如下:

/**     * Initialize the MessageSource.     * Use parent's if none defined in this context.     */    protected void initMessageSource() {        ConfigurableListableBeanFactory beanFactory = getBeanFactory();        if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {            this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);            // Make MessageSource aware of parent MessageSource.            if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {                HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;                if (hms.getParentMessageSource() == null) {                    // Only set parent context as parent MessageSource if no parent MessageSource                    // registered already.                    hms.setParentMessageSource(getInternalParentMessageSource());                }            }            if (logger.isTraceEnabled()) {                logger.trace("Using MessageSource [" + this.messageSource + "]");            }        }        else {            // Use empty MessageSource to be able to accept getMessage calls.            DelegatingMessageSource dms = new DelegatingMessageSource();            dms.setParentMessageSource(getInternalParentMessageSource());            this.messageSource = dms;            beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);            if (logger.isTraceEnabled()) {                logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");            }        }    }

DelegatingMessageSource仅仅代理AbstractApplicationContext父类中的messageSource实例,或者父AbstractApplicationContext(因为AbstractApplicationContext实现了MessageSource的接口)。

AbstractApplicationContext也实现了MessageSource的接口,相干的实现都是通过委托外部的messageSource进行解决的。源码如下:

 @Overridepublic String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale) {   return getMessageSource().getMessage(code, args, defaultMessage, locale);}@Overridepublic String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {   return getMessageSource().getMessage(code, args, locale);}@Overridepublic String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {   return getMessageSource().getMessage(resolvable, locale);}private MessageSource getMessageSource() throws IllegalStateException {   if (this.messageSource == null) {      throw new IllegalStateException("MessageSource not initialized - " +            "call 'refresh' before accessing messages via the context: " + this);   }   return this.messageSource;}

我的项目中,咱们如果想应用国际化的内容,须要配置一个名字为“messageResource”的MessageResouce实例,能够应用spring开箱即用的现有实现(ResourceBundle 和 MessageFormat的合集)。