Spring国际化消息解析原理

Spring的国际化消息

spring的国际化接口是MessageSource,他有很多实现了,这里以ResourceBundleMessageSource来说明它的原理。

总体流程:

总体流程的代码:

MessageFormat messageFormat = resolveCode(code, locale);
if (messageFormat != null) {
    synchronized (messageFormat) {
        return messageFormat.format(argsToUse);
    }
}
测试代码

public class Main {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext app =
                new ClassPathXmlApplicationContext("com/firefish/springsourcecodedeepanalysis/i18n/application.xml");
        Object[] param = {"John", new GregorianCalendar().getTime()};

        String test1 = app.getMessage("test", param, Locale.US);
        String test2 = app.getMessage("test", param, Locale.CHINA);
        System.out.println(test1);
        System.out.println(test2);
    }
}
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>i18n/messages</value>
            </list>
        </property>
    </bean>
// messages.properties文件内容
test=test

// mmessages_en_US.properties文件内容
test=test

// messages_zh_CN.properties文件内容
test=测试
原理分析
1、程序入口

ClassPathXmlApplicationContext容器加载的时候会去初始化国际化消息,这里会把我们配置好的ResourceBundleMessageSource对象初始化好,之后就是调用这个对象的方法完成功能。

// Initialize message source for this context.
// 7、为应用初始化message源,为了"国际化"。国际化的入口
initMessageSource();

随着app.getMessage("test", param, Locale.US);代码的执行,会依次执行

2、获取ResourceBundle

结果漫长的方法调用,我们到了loadBundle,newBundle方法,这个方法有一段代码,功能是拼接处文件的名称,用类加载器完成文件的加载,随后把结果缓存起来。

// 根据baseName和locale获取bundleName的名称。如messages_zh_CN
String bundleName = toBundleName(baseName, locale);
// 再把properties后缀拼接上,得到完成名称
final String resourceName = toResourceName(bundleName, "properties");
// 用类加载器加载了文件
URL url = classLoader.getResource(resourceName);
3、转换为javase的MessageFormat

直接看代码。

    protected MessageFormat resolveCode(String code, Locale locale) {
        Set<String> basenames = getBasenameSet();
        for (String basename : basenames) {
            ResourceBundle bundle = getResourceBundle(basename, locale);
            if (bundle != null) {
                // 获取到code在特定locale下的值
                MessageFormat messageFormat = getMessageFormat(bundle, code, locale);
                if (messageFormat != null) {
                    return messageFormat;
                }
            }
        }
        return null;
    }
4、应用javase的MessageFormat的format

直接看代码。

if (messageFormat != null) {
    synchronized (messageFormat) {
        // javase完成实际变量替换占位符参数
        return messageFormat.format(argsToUse);
    }
}

传送门:保姆式Spring5源码解析

欢迎与作者一起交流技术和工作生活

联系作者

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fire Fish

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值