Spring boot 國際化自動加載資源文件問題

Spring boot 國際化自動加載資源文件問題

  最近在作基於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

相關文章
相關標籤/搜索