1 概述
initMessageSource主要用于国际化,说简单点就是不同语言之间的翻译
2 应用
2.1 添加Bean
在Spring的配置文件中名称为messageSource(名称不能错,否则读取失效!)的Bean
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<!-- 中文和其他语言的文件名开头 -->
<value>message_source</value>
</list>
</property>
<!-- 避免中文乱码 -->
<property name="defaultEncoding">
<value>UTF-8</value>
</property>
</bean>
2.2 新增配置文件
博主是maven工程,在{$projectname}/src/main/resources目录下新增两个文件
1)message_source_en.properties
往文件写入:
// 英文版文件的内容
author=baby
2)message_source_zh.properties
往文件写入:
// 中文版文件的内容
author=宝宝
2.3 启动类
public class BeanLifeCycle{
public static void main(String[] args) {
System.out.println("现在开始初始化容器");
ApplicationContext factory = new ClassPathXmlApplicationContext("beans.xml");
System.out.println("容器初始化成功");
// ch
String cnAuthor = factory.getMessage("author", new Object[] {}, Locale.CHINESE);
System.out.println(cnAuthor);
// en
String enAuthor = factory.getMessage("author", new Object[] {}, Locale.ENGLISH);
System.out.println(enAuthor);
System.out.println("现在开始关闭容器!");
((ClassPathXmlApplicationContext) factory).close();
}
}
2.4 日志
宝宝
baby
3 源码
3.1 initMessageSource方法
protected void initMessageSource() {
//获取bean工厂
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//判断配置文件中是否包含名称为messageSource的Bean
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
//获取名称为messageSource的Bean,若不存在则触发Bean的创建
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// Make MessageSource aware of parent MessageSource.
//判断父类是否不为空且当前对象的messageSource是HierarchicalMessageSource的一个实例
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
//转型
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
//判断父MessageSource是否为空
if (hms.getParentMessageSource() == null) {
// Only set parent context as parent MessageSource if no parent MessageSource
// registered already.
//将 hms的父MessageSource赋值为getInternalParentMessageSource
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// Use empty MessageSource to be able to accept getMessage calls.
//配置文件中不存在名为messageSource的Bean,则手动创建一个DelegatingMessageSource实例,用于接受getMessage方法调用。
//DelegatingMessageSource本质上也是MessageSource接口的实现类
DelegatingMessageSource dms = new DelegatingMessageSource();
//添加父类消息源
dms.setParentMessageSource(getInternalParentMessageSource());
//赋值
this.messageSource = dms;
//以messageSource为BeanNme 将DelegatingMessageSource类的实例注册到一级缓存singletonObjects中
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isTraceEnabled()) {
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
}
}
}
3.2 getInternalParentMessageSource方法
protected MessageSource getInternalParentMessageSource() {
//判断父类上下文是不是AbstractApplicationContext的子类
//若是,则返回父类上下文的messageSource
//若不是,则返回父类
return (getParent() instanceof AbstractApplicationContext ?
((AbstractApplicationContext) getParent()).messageSource : getParent());
}
3.3 registerSingleton方法
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
//添加到一级缓存中
super.registerSingleton(beanName, singletonObject);
//入参是JDK8新特性,函数式接口Consumer和Predicate
updateManualSingletonNames(set -> set.add(beanName), set -> !this.beanDefinitionMap.containsKey(beanName));
clearByTypeCache();
}
3.4 updateManualSingletonNames方法
private void updateManualSingletonNames(Consumer<Set<String>> action, Predicate<Set<String>> condition) {
//检查工厂的bean创建阶段是否已经开始
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
//判断beanDefinitionMap是否包含当前beanName,若是则返回false
if (condition.test(this.manualSingletonNames)) { //这个入参在方法实际中并没有参与布尔运算符的计算
//新实例化一个Set,用于存储系统手动生成的单例Bean的BeanName(区别于Spring配置文件中添加的bean)
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
//将当前beanName添加到updatedSingletons中
action.accept(updatedSingletons);
//重新赋值
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
// 工厂还处在注册阶段
if (condition.test(this.manualSingletonNames)) {
//将当前beanName添加到manualSingletonNames
action.accept(this.manualSingletonNames);
}
}
}
3.5 clearByTypeCache方法
/** Map of singleton and non-singleton bean names, keyed by dependency type. */
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
/** Map of singleton-only bean names, keyed by dependency type. */
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);
private void clearByTypeCache() {
//清空l容器中数据
this.allBeanNamesByType.clear();
this.singletonBeanNamesByType.clear();
}
四 参考文献
1)JDK7在线文档
https://tool.oschina.net/apidocs/apidoc?api=jdk_7u4
2) JDK8在线文档
https://docs.oracle.com/javase/8/docs/api/
3)Spring Framework 5 中文文档
https://www.cntofu.com/book/95/index.html
4) Bruce Eckel. Java编程思想,第4版,2007,机械工业出版社
5)方腾飞,魏鹏,程晓明. Java并发编程的艺术,第1版,2015年,机械工业出版社
6)克雷格.沃斯. Spring实战,第5版,2020年,人民邮电出版社