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的国际化支持,实现国际化的开箱即用,静态文件配置刷新生效以及全局异常国际化处理。
776 0
从MessageSource源码出发实战spring·i18n国际化的三种改造方案
|
Java 测试技术 Spring
Spring-国际化信息02-MessageSource接口
Spring-国际化信息02-MessageSource接口
178 0
|
Java Spring 容器
Spring 国际化支持之 MessageSource
背景 为了友好的支持各个国家的语言,Java 本身已经提供了对国际化的支持,上篇文章《Java 国际化与文本格式化》已经介绍了 Java 对国际化的支持。
373 0
|
缓存 Java 测试技术
Spring(21)——国际化MessageSource
21 国际化MessageSource Spring中定义了一个MessageSource接口,以用于支持信息的国际化和包含参数的信息的替换。MessageSource接口的定义如下,对应的方法说明已经在方法上注释了。
1221 0
|
Java Spring 安全
Spring的国际化资源messageSource
Spring中可以使用两个类加载资源文件:ReloadableResourceBundleMessageSource和ResourceBundleMessageSource。 可配置如下messageSource这个bean id不能变: @Bean public MessageS...
1415 0
|
Java 测试技术 Spring
Spring messageSource
Spring中可以使用两个类加载资源文件: org.springframework.context.support.ReloadableResourceBundleMessageSource 和 org.
1074 0
|
30天前
|
XML Java 应用服务中间件
Spring Boot 两种部署到服务器的方式
本文介绍了Spring Boot项目的两种部署方式:jar包和war包。Jar包方式使用内置Tomcat,只需配置JDK 1.8及以上环境,通过`nohup java -jar`命令后台运行,并开放服务器端口即可访问。War包则需将项目打包后放入外部Tomcat的webapps目录,修改启动类继承`SpringBootServletInitializer`并调整pom.xml中的打包类型为war,最后启动Tomcat访问应用。两者各有优劣,jar包更简单便捷,而war包适合传统部署场景。需要注意的是,war包部署时,内置Tomcat的端口配置不会生效。
251 17
Spring Boot 两种部署到服务器的方式
|
30天前
|
Dart 前端开发 JavaScript
springboot自动配置原理
Spring Boot 自动配置原理:通过 `@EnableAutoConfiguration` 开启自动配置,扫描 `META-INF/spring.factories` 下的配置类,省去手动编写配置文件。使用 `@ConditionalXXX` 注解判断配置类是否生效,导入对应的 starter 后自动配置生效。通过 `@EnableConfigurationProperties` 加载配置属性,默认值与配置文件中的值结合使用。总结来说,Spring Boot 通过这些机制简化了开发配置流程,提升了开发效率。
63 17
springboot自动配置原理
|
1月前
|
XML JavaScript Java
SpringBoot集成Shiro权限+Jwt认证
本文主要描述如何快速基于SpringBoot 2.5.X版本集成Shiro+JWT框架,让大家快速实现无状态登陆和接口权限认证主体框架,具体业务细节未实现,大家按照实际项目补充。
88 11
|
1月前
|
缓存 安全 Java
Spring Boot 3 集成 Spring Security + JWT
本文详细介绍了如何使用Spring Boot 3和Spring Security集成JWT,实现前后端分离的安全认证概述了从入门到引入数据库,再到使用JWT的完整流程。列举了项目中用到的关键依赖,如MyBatis-Plus、Hutool等。简要提及了系统配置表、部门表、字典表等表结构。使用Hutool-jwt工具类进行JWT校验。配置忽略路径、禁用CSRF、添加JWT校验过滤器等。实现登录接口,返回token等信息。
375 12