Spring5 IOC源码解读系列7—initMessageSource方法

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年,人民邮电出版社

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值