国际化主要是引入了MessageSource,咱们简单看下如何使用,以及其原理。java
1.1 设置资源文件
在 properties新建i18n目录spring
新建message文件:缓存
messages.propertiesapp
error.title=Your request cannot be processed
messages_zh_CN.propertieside
error.title=您的请求没法处理
1.2 配置
修改properties文件的目录:在application.yml或者application.properties中配置 spring.message.basenamefetch
spring: application: name: test-worklog messages: basename: i18n/messages encoding: UTF-8
1.3 使用
引用自动注解的MessageSource,调用messageSource.getMessage
便可,注意,须要经过 LocaleContextHolder.getLocale()
获取当前的地区。ui
@Autowired private MessageSource messageSource; /** * 国际化 * * @param result * @return */ public String getMessage(String result, Object[] params) { String message = ""; try { Locale locale = LocaleContextHolder.getLocale(); message = messageSource.getMessage(result, params, locale); } catch (Exception e) { LOGGER.error("parse message error! ", e); } return message; }
如何设置个性化的地区呢? forLanguageTag
便可this
Locale locale = Locale.forLanguageTag(user.getLangKey());
1.4 原理分析
MessageSourceAutoConfiguration
中,实现了autoconfigurl
@Configuration @ConditionalOnMissingBean(value = MessageSource.class, search = SearchStrategy.CURRENT) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @Conditional(ResourceBundleCondition.class) @EnableConfigurationProperties @ConfigurationProperties(prefix = "spring.messages") public class MessageSourceAutoConfiguration {
该类一方面读取配置文件,一方面建立了MessageSource的实例:spa
@Bean public MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); if (StringUtils.hasText(this.basename)) { messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray( StringUtils.trimAllWhitespace(this.basename))); } if (this.encoding != null) { messageSource.setDefaultEncoding(this.encoding.name()); } messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale); messageSource.setCacheSeconds(this.cacheSeconds); messageSource.setAlwaysUseMessageFormat(this.alwaysUseMessageFormat); return messageSource; }
所以,默认是加载的ResourceBundleMessageSource
,该类派生与于AbstractResourceBasedMessageSource
@Override public final String getMessage(String code, Object[] args, String defaultMessage, Locale locale) { String msg = getMessageInternal(code, args, locale); if (msg != null) { return msg; } if (defaultMessage == null) { String fallback = getDefaultMessage(code); if (fallback != null) { return fallback; } } return renderDefaultMessage(defaultMessage, args, locale); }
最终是调用resolveCode来获取message,经过ResourceBundle来获取message
@Override protected MessageFormat resolveCode(String code, Locale locale) { // 遍历语言文件路径 Set<String> basenames = getBasenameSet(); for (String basename : basenames) { ResourceBundle bundle = getResourceBundle(basename, locale); if (bundle != null) { MessageFormat messageFormat = getMessageFormat(bundle, code, locale); if (messageFormat != null) { return messageFormat; } } } return null; } // 获取ResourceBundle protected ResourceBundle getResourceBundle(String basename, Locale locale) { if (getCacheMillis() >= 0) { // Fresh ResourceBundle.getBundle call in order to let ResourceBundle // do its native caching, at the expense of more extensive lookup steps. return doGetBundle(basename, locale); } else { // Cache forever: prefer locale cache over repeated getBundle calls. synchronized (this.cachedResourceBundles) { Map<Locale, ResourceBundle> localeMap = this.cachedResourceBundles.get(basename); if (localeMap != null) { ResourceBundle bundle = localeMap.get(locale); if (bundle != null) { return bundle; } } try { ResourceBundle bundle = doGetBundle(basename, locale); if (localeMap == null) { localeMap = new HashMap<Locale, ResourceBundle>(); this.cachedResourceBundles.put(basename, localeMap); } localeMap.put(locale, bundle); return bundle; } catch (MissingResourceException ex) { if (logger.isWarnEnabled()) { logger.warn("ResourceBundle [" + basename + "] not found for MessageSource: " + ex.getMessage()); } // Assume bundle not found // -> do NOT throw the exception to allow for checking parent message source. return null; } } } } // ResourceBundle protected ResourceBundle doGetBundle(String basename, Locale locale) throws MissingResourceException { return ResourceBundle.getBundle(basename, locale, getBundleClassLoader(), new MessageSourceControl()); }
最后来看getMessageFormat:
/** * Return a MessageFormat for the given bundle and code, * fetching already generated MessageFormats from the cache. * @param bundle the ResourceBundle to work on * @param code the message code to retrieve * @param locale the Locale to use to build the MessageFormat * @return the resulting MessageFormat, or {@code null} if no message * defined for the given code * @throws MissingResourceException if thrown by the ResourceBundle */ protected MessageFormat getMessageFormat(ResourceBundle bundle, String code, Locale locale) throws MissingResourceException { synchronized (this.cachedBundleMessageFormats) { // 从缓存读取 Map<String, Map<Locale, MessageFormat>> codeMap = this.cachedBundleMessageFormats.get(bundle); Map<Locale, MessageFormat> localeMap = null; if (codeMap != null) { localeMap = codeMap.get(code); if (localeMap != null) { MessageFormat result = localeMap.get(locale); if (result != null) { return result; } } } // 缓存miss,从bundle读取 String msg = getStringOrNull(bundle, code); if (msg != null) { if (codeMap == null) { codeMap = new HashMap<String, Map<Locale, MessageFormat>>(); this.cachedBundleMessageFormats.put(bundle, codeMap); } if (localeMap == null) { localeMap = new HashMap<Locale, MessageFormat>(); codeMap.put(code, localeMap); } MessageFormat result = createMessageFormat(msg, locale); localeMap.put(locale, result); return result; } return null; } }
做者:Jadepeng 出处:jqpeng的技术记事本--http://www.cnblogs.com/xiaoqi 您的支持是对博主最大的鼓励,感谢您的认真阅读。 本文版权归做者全部,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然保留追究法律责任的权利。