每天进步一点点,大家好,我是大龄码农。
今天我们聊聊Spring中国际化的源码。
细心的朋友可能发现了,在Spring—国际化这篇文章的实践中,定义了messageSource对象,尽管在测试类中没用到,但是依然输出了想要的正确结果,这是为什么呢?我们进入源码一探究竟。







说明:结合着代码看,逻辑就很清晰了。如果容器中有定义名为“messageSource”的bean,就使用这个bean,如果没有就创建DelegatingMessageSource对象。
MessageSource接口的方法实现类

说明:通过上面的分析,大家应该也知道了,我们可以把重点放在AbstractMessageSource类上

说明:其他两个方法大同小异。
那么,我们就来看看这里面的两个方法:
一、getMessageInternal()
这个方法可以分三部分看,无参、有参、公共配置
注:这里的参数是指消息中可以被动态填充的内容
1、无参

说明:其实这个方法已经被一些常用类重写了。进到这个类简单看下

说明1:resolveCode()是个抽象方法,需要被子类实现,用于处理消息
说明2:关于MessageFormat,类似的Format实现类还有:

2、有参

说明:先处理参数,resolveCode需要被子类实现

说明:其实就是将Object[]数组转化为List,只是其中增加了一个递归拆解消息的动作
3、公共配置

说明:getCommonMessages()方法就是获取对应的属性

说明:如果在资源文件中没找到时,就会到公共配置中查找。如果找不到,就会再去查找parentMessageSource(如果配置的话)
二、getDefaultMessage()
如果上面都查不到的话,就来到了这个方法。其实这个方法是对应入参类型为MessageSourceResolvable的getMessages()方法
最后,如果都找不到的话,就会抛出异常NoSuchMessageException
常用类
ResourceBundleMessageSource

说明:这是一个比较常用的实现类,通过定义多个properties资源文件,在创建ResourceBundleMessageSource时将定义的资源文件名注入到其basenameSet属性中。当项目启动后,就可以读取资源文件中的配置信息
我们以resolveCodeWithoutArguments()方法为例,看一下在这个类中是如何重写父类的方法的

说明:我们看一下getResourceBundle()方法


说明:doGetBundle()就是获取对应的资源文件,这个方法就不展开讲了,其中定义了一个CacheKey类

说明:这里创建LoaderReference类,它继承了弱引用。

同时,还有一个BundleReference类,它继承了软引用

说明:弱引用和软引用都可以被垃圾回收器回收
我们回到前面的方法,ResourceBundleMessageSource默认是一个带有缓存功能的类,如果设置了cacheMillis值大于0,则不会走缓存的判断分支,而是有种实现了动态加载静态文件的效果。
注:在生产环境上不能将cacheMillis值设置为0,因为在每次信息访问时都会校验

说明:缓存的数据类型
ReloadableResourceBundleMessageSource
看名字就能知道,它有可重加载的功能,简单说下与ResourceBundleMessageSource的区别:
ReloadableResourceBundleMessageSource | ||
静态文件的刷新(cacheMillis值大于0) |
对于该类的具体实现细节,有兴趣的同学,可以去研究下。
实践
一、带参数的消息

测试类

说明:我只在一个资源文件中配置了信息,所以测试时必须指定Locale,否则会抛出异常。这个例子比较巧,因为默认Locale就是zh_CN

问题:如果不传入参数值呢?


回答:就不替换占位符呗
二、公共配置

说明:这里只是简单说明下,当然也可以使用读取配置文件的形式


三、默认方法


说明:大家看下效果就好,主要就是用实例说明一下源码
夜雨聆风