Spring MessageSource详解

简介: 《基础系列》

初始化入口

  • org.springframework.context.support.AbstractApplicationContext.refresh方法有initMessageSource()方法进行了MessageSource初始化
protected void initMessageSource() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        // 判断是否含有 messageSource
        if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
            // 读取xml配置文件中 id="messageSource"的数据
            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
            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 + "]");
            }
        }
    }
Copy to clipboardErrorCopied

读取 xml 配置文件

1.png

getMessage

  • org.springframework.context.support.AbstractApplicationContext#getMessage(java.lang.String, java.lang.Object[], java.util.Locale)
@Override
    public String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
        return getMessageSource().getMessage(code, args, locale);
    }
Copy to clipboardErrorCopied
  • org.springframework.context.support.AbstractMessageSource#getMessage(java.lang.String, java.lang.Object[], java.util.Locale)
@Override
    public final String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
        // 获取对应的信息
        String msg = getMessageInternal(code, args, locale);
        if (msg != null) {
            return msg;
        }
        // 默认信息 null
        String fallback = getDefaultMessage(code);
        if (fallback != null) {
            return fallback;
        }
        throw new NoSuchMessageException(code, locale);
    }
Copy to clipboardErrorCopied
  • 两个方法
  1. org.springframework.context.support.AbstractMessageSource#getDefaultMessage(java.lang.String)
@Nullable
    protected String getDefaultMessage(String code) {
        // 判断是否使用默认值
        if (isUseCodeAsDefaultMessage()) {
            return code;
        }
        return null;
    }
Copy to clipboardErrorCopied
  • 返回 code 本身或者null
  1. org.springframework.context.support.AbstractMessageSource#getMessageInternal
@Nullable
    protected String getMessageInternal(@Nullable String code, @Nullable Object[] args, @Nullable Locale locale) {
        if (code == null) {
            return null;
        }
        if (locale == null) {
            // 获取语言默认值
            locale = Locale.getDefault();
        }
        Object[] argsToUse = args;
        if (!isAlwaysUseMessageFormat() && ObjectUtils.isEmpty(args)) {
            // Optimized resolution: no arguments to apply,
            // therefore no MessageFormat needs to be involved.
            // Note that the default implementation still uses MessageFormat;
            // this can be overridden in specific subclasses.
            String message = resolveCodeWithoutArguments(code, locale);
            if (message != null) {
                return message;
            }
        }
        else {
            // Resolve arguments eagerly, for the case where the message
            // is defined in a parent MessageSource but resolvable arguments
            // are defined in the child MessageSource.
            argsToUse = resolveArguments(args, locale);
            MessageFormat messageFormat = resolveCode(code, locale);
            if (messageFormat != null) {
                synchronized (messageFormat) {
                    return messageFormat.format(argsToUse);
                }
            }
        }
        // Check locale-independent common messages for the given message code.
        Properties commonMessages = getCommonMessages();
        if (commonMessages != null) {
            String commonMessage = commonMessages.getProperty(code);
            if (commonMessage != null) {
                return formatMessage(commonMessage, args, locale);
            }
        }
        // Not found -> check parent, if any.
        return getMessageFromParent(code, argsToUse, locale);
    }
Copy to clipboardErrorCopied
  • org.springframework.context.support.ResourceBundleMessageSource#resolveCodeWithoutArguments
@Override
    protected String resolveCodeWithoutArguments(String code, Locale locale) {
        Set<String> basenames = getBasenameSet();
        for (String basename : basenames) {
            // 加载 basename
            ResourceBundle bundle = getResourceBundle(basename, locale);
            if (bundle != null) {
                // 从basename对应的文件中获取对应的值
                String result = getStringOrNull(bundle, code);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }
Copy to clipboardErrorCopied

2.png

  • 加载后截图
    获取方法String result = getStringOrNull(bundle, code);就是 map 获取

4.png

  • 没有配置文件的情况
  • 5.png
相关文章
|
XML 存储 缓存
从MessageSource源码出发实战spring·i18n国际化的三种改造方案
从源码去看MessageSource的几个实现类的源码出发,基于spring的国际化支持,实现国际化的开箱即用,静态文件配置刷新生效以及全局异常国际化处理。
1167 0
从MessageSource源码出发实战spring·i18n国际化的三种改造方案
|
Java 测试技术 Spring
Spring-国际化信息02-MessageSource接口
Spring-国际化信息02-MessageSource接口
333 0
|
Java Spring 容器
Spring 国际化支持之 MessageSource
背景 为了友好的支持各个国家的语言,Java 本身已经提供了对国际化的支持,上篇文章《Java 国际化与文本格式化》已经介绍了 Java 对国际化的支持。
573 0
|
缓存 Java 测试技术
Spring(21)——国际化MessageSource
21 国际化MessageSource Spring中定义了一个MessageSource接口,以用于支持信息的国际化和包含参数的信息的替换。MessageSource接口的定义如下,对应的方法说明已经在方法上注释了。
1328 0
|
Java Spring 安全
Spring的国际化资源messageSource
Spring中可以使用两个类加载资源文件:ReloadableResourceBundleMessageSource和ResourceBundleMessageSource。 可配置如下messageSource这个bean id不能变: @Bean public MessageS...
1540 0
|
Java 测试技术 Spring
Spring messageSource
Spring中可以使用两个类加载资源文件: org.springframework.context.support.ReloadableResourceBundleMessageSource 和 org.
1166 0
|
7月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1184 0
|
8月前
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
958 0
|
4月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
471 3
|
4月前
|
Java 测试技术 数据库连接
【SpringBoot(四)】还不懂文件上传?JUnit使用?本文带你了解SpringBoot的文件上传、异常处理、组件注入等知识!并且带你领悟JUnit单元测试的使用!
Spring专栏第四章,本文带你上手 SpringBoot 的文件上传、异常处理、组件注入等功能 并且为你演示Junit5的基础上手体验
997 2

热门文章

最新文章