最近在作基於Spring boot配置的項目。中間遇到一個國際化資源加載的問題,正常來講只要在application.properties文件中定義正確的資源文件路徑,Spring boot就啓動時就會自動加載資源。java
spring.messages.basename=i18n/message
可是個人項目修改後獲取消息時系統報錯,找不到對應語言的資源配置。因而試圖找到緣由。Google很久都沒找到,簡直好像就我一我的遇到這鬼問題同樣🙄。只好本身一步一步去調試。spring
調試中首先發現系統在調用MessageSource的地方注入的不是MessageSourceAutoConfiguration中定義的ResourceBundleMessageSource對象,而是一個DelegatingMessageSource對象,並且這個對象是空的什麼都沒有。MessageSourceAutoConfiguration中的定義以下:segmentfault
@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; }
調試Spring boot 啓動過程找到了 DelegatingMessageSource 對象來源, 在啓動過程當中若是Spring沒有找到messageSource定義,就會自動建立一個 DelegatingMessageSource 對象提供給SpringContext。也就是說 MessageSourceAutoConfiguration 根本沒有被加載。打斷點在 MessageSourceAutoConfiguration 中也肯定了Spring boot啓動時根本沒有執行 MessageSourceAutoConfiguration 的定義。app
/** * 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.isDebugEnabled()) { logger.debug("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.isDebugEnabled()) { logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME + "': using default [" + this.messageSource + "]"); } } }
繼續調試發現 MessageSourceAutoConfiguration 上有 @Conditional(ResourceBundleCondition.class) 這麼個註解,@Conditional 官方介紹 Indicates that a component is only eligible for registration when all specified conditions match. 大概意思就是隻有知足全部條件纔會被註冊。繼續去看ResourceBundleCondition.class的實現。post
private ConditionOutcome getMatchOutcomeForBasename(ConditionContext context, String basename) { ConditionMessage.Builder message = ConditionMessage .forCondition("ResourceBundle"); for (String name : StringUtils.commaDelimitedListToStringArray( StringUtils.trimAllWhitespace(basename))) { for (Resource resource : getResources(context.getClassLoader(), name)) { if (resource.exists()) { return ConditionOutcome .match(message.found("bundle").items(resource)); } } } return ConditionOutcome.noMatch( message.didNotFind("bundle with basename " + basename).atAll()); }
這個方法是根據basename(上面配置的「i18n/message」)存不存在返回是否知足條件,也就是去找classpath:i18n/message.properties文件,看了下目錄確實沒有這個文件(只有message_**.properties)。由於以前項目messageSource加載時本身配置的,因此並無這個問題。但如今Spring boot中沒有找到message.properties這個默認文件整個messageSource就不加載了。。🙄簡直思密達。。。🎉🎉總算是解決這個奇葩問題。 話說真的就只有我遇到這問題麼,沒搜到沒搜到啊。。。。😢ui
最後總結Spring boot自動加載messageSource必定要有一個默認的資源文件。也就是basename.properties。好不科學啊,以前沒有找到默認會默認取中文(沒考慮過原理😆),如今沒有默認整個就不加載了。this
注:文章轉自 http://www.javashuo.com/article/p-ztxlsoqu-hg.htmlspa