Spring源码系列【四】——Context初始化流程(下)

Context 初始化流程

接上一篇:Spring源码系列【三】——Context初始化流程(上)

二、方法详解

2.7 #initMessageSource()

初始化消息源,消息源可用来支持消息的国际化。

/**
 * Initialize the MessageSource.
 * Use parent's if none defined in this context.
 * 初始化MessageSource
 * 如果在上下文中未定义,则使用父项
 */
protected void initMessageSource() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
                // 如果在配置中已经配置了messageSource,那么将messageSource提取并记录在this.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.
				// 如果尚未注册父MessageSource,则仅将父上下文设置为父MessageSource
				hms.setParentMessageSource(getInternalParentMessageSource());
			}
		}
		if (logger.isTraceEnabled()) {
			logger.trace("Using MessageSource [" + this.messageSource + "]");
		}
	}
	else {
		// Use empty MessageSource to be able to accept getMessage calls.
		// 使用空的MessageSource可以接受getMessage调用(如果用户并没有定义配置文件,那么使用临时的DelegatingMessageSource以便于作为调用getMessage方法返回)
		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 + "]");
		}
	}
}

可以查看 MessageSource.java 接口:用于解析消息的策略界面,支持参数化以及此类信息的国际化。

如图getMessage():

大致意思就是,通过读取并将自定义资源文件配置记录在容器中,那么就可以在获取资源文件的时候使用了,例如在 AbstractApplicationContext 中的获取资源文件属性的方法就是:

return getMessageSource().getMessage(code, args, locale);

 

2.8 #initApplicationEventMulticaster()

初始化应用事件广播器。事件广播器用来向 ApplicationListener 通知各种应用产生的事件,是标准的观察者模式。

/**
 * Initialize the ApplicationEventMulticaster.
 * Uses SimpleApplicationEventMulticaster if none defined in the context.
 * 初始化ApplicationEventMulticaster
 * 如果上下文中未定义,则使用SimpleApplicationEventMulticaster
 * @see org.springframework.context.event.SimpleApplicationEventMulticaster
 */
protected void initApplicationEventMulticaster() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
		this.applicationEventMulticaster =
				beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
		if (logger.isTraceEnabled()) {
			logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
		}
	}
	else {
		this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
		beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
		if (logger.isTraceEnabled()) {
			logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
					"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
		}
	}
}

初始化广播器逻辑考虑两种情况:如果用户自定义了事件广播器,就使用自定义的事件广播器,如果用户没有定义,则使用默认的 ApplicationEventMulticaster。其中 new SimpleApplicationEventMulticaster(beanFactory); 就是默认广播器的实现。

 

2.9 #onRefresh()

该方法是留给子类的扩展步骤,用来让特定的 Context 子类初始化其他的 Bean。

/**
 * Template method which can be overridden to add context-specific refresh work.
 * Called on initialization of special beans, before instantiation of singletons.
 * 可以重写的模版方法以添加特定于上下文的刷新操作
 * 在所有单例bean初始化之前调用
 * <p>This implementation is empty.
 * @throws BeansException in case of errors
 * @see #refresh()
 */
protected void onRefresh() throws BeansException {
	// For subclasses: do nothing by default.
}

 

2.10 #registerListeners()

把实现了ApplicationListener 的 Bean 注册到事件广播器,并对广播器中的早期未广播事件进行通知。

/**
 * Add beans that implement ApplicationListener as listeners.
 * Doesn't affect other listeners, which can be added without being beans.
 */
protected void registerListeners() {
	// Register statically specified listeners first.
	// 首先注册静态指定的监听器
	for (ApplicationListener<?> listener : getApplicationListeners()) {
		getApplicationEventMulticaster().addApplicationListener(listener);
	}

	// Do not initialize FactoryBeans here: We need to leave all regular beans
	// uninitialized to let post-processors apply to them!
	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
	for (String listenerBeanName : listenerBeanNames) {
		getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
	}

	// Publish early application events now that we finally have a multicaster...
	// 至此拥有了一个广播器,可以发布早起的应用程序事件
	Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
	this.earlyApplicationEvents = null;
	if (earlyEventsToProcess != null) {
		for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
			getApplicationEventMulticaster().multicastEvent(earlyEvent);
		}
	}
}

 

2.11 #finishBeanFactoryInitialization()

完成 BeanFactory 的初始化工作,其中包括 ConversionService 的设置、配置冻结以及非延迟加载的 bean 的初始化工作。

/**
 * Finish the initialization of this context's bean factory,
 * initializing all remaining singleton beans.
 * 完成此上下文的BeanFactory的初始化
 * 初始化所有剩余的单例bean
 */
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// Initialize conversion service for this context.
	// 为此上下文初始化转换服务
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
			beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
		beanFactory.setConversionService(
				beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
	}

	// Register a default embedded value resolver if no bean post-processor
	// (such as a PropertyPlaceholderConfigurer bean) registered any before:
	// at this point, primarily for resolution in annotation attribute values.
	// 如果没有bean后处理器,则注册默认的嵌入式值解析器(例如PropertyPlaceholderConfigurer bean)之前注册过的任何东西:
	// 主要用于注释属性值的解析。
	if (!beanFactory.hasEmbeddedValueResolver()) {
		beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
	}

	// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
	// 尽早初始化LoadTimeWeaverAware bean,以便尽早注册其转换器
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}

	// Stop using the temporary ClassLoader for type matching.
	// 停止使用临时的类加载器进行类型匹配
	beanFactory.setTempClassLoader(null);

	// Allow for caching all bean definition metadata, not expecting further changes.
	// 允许缓存所有bean定义元数据,而不期望进一步的更改
	beanFactory.freezeConfiguration();

	// Instantiate all remaining (non-lazy-init) singletons.
	// 初始化所有剩余的单例bean(非延迟初始化的)
	beanFactory.preInstantiateSingletons();
}

 

2.12 #finishRefresh()

完成上下文的 refresh 工作,调用 LifecycleProcessor 的 onFresh() 方法,以及发布 ContextRefreshEvent 事件。

/**
 * Finish the refresh of this context, invoking the LifecycleProcessor's
 * onRefresh() method and publishing the
 * {@link org.springframework.context.event.ContextRefreshedEvent}.
 * 完成此上下文的刷新,调用LifecycleProcessor的onRefresh()方法并发布
 */
protected void finishRefresh() {
	// Clear context-level resource caches (such as ASM metadata from scanning).
	// 清除上下文级别的资源缓存,例如来自扫描的ASM元数据
	clearResourceCaches();

	// Initialize lifecycle processor for this context.
	// 为此上下文初始化生命周期处理器
	initLifecycleProcessor();

	// Propagate refresh to lifecycle processor first.
	// 首先将刷新传播到生命周期处理器
	getLifecycleProcessor().onRefresh();

	// Publish the final event.
	// 发布最终事件
	publishEvent(new ContextRefreshedEvent(this));

	// Participate in LiveBeansView MBean, if active.
	// 如果是活动的,则加入到LiveBeansView MBean
	LiveBeansView.registerApplicationContext(this);
}

Spring 中提供了 Lifecycle 接口,该接口中包含 start 和 stop 方法,实现此接口后 Spring 会保证在启动的时候调用 start 方法开始生命周期,并在 Spring 关闭的时候调用 stop 方法来结束生命周期,通常用于配置后台程序,在启动后一直运行(比如对 MQ 进行轮询等)。ApplicationContext 的初始化最后正是保证了这一功能的实现。

  • initLifecycleProcessor

当 ApplicationContext 启动或停止时,它会通过 LifecycleProcessor 来与所有声明的 bean 的周期做状态更新,而在 LifecycleProcessor 使用之前需要初始化。

  • onRefresh

启动所有实现了 Lifecycle 接口的bean。

  • publishEvent

当完成 ApplicationContext 初始化的时候,要通过 Spring 中的事件发布机制发出 ContextRefreshedEvent 事件,以保证对应的监听器可以做进一步的逻辑处理。

 

2.13 #resetCommonCaches()

在 finally 中重置公共的缓存,比如 ReflectionUtils 中的缓存、AnnotationUtils 中的缓存。

/**
 * Reset Spring's common reflection metadata caches, in particular the
 * {@link ReflectionUtils}, {@link AnnotationUtils}, {@link ResolvableType}
 * and {@link CachedIntrospectionResults} caches.
 * @since 4.2
 * @see ReflectionUtils#clearCache()
 * @see AnnotationUtils#clearCache()
 * @see ResolvableType#clearCache()
 * @see CachedIntrospectionResults#clearClassLoader(ClassLoader)
 */
protected void resetCommonCaches() {
	ReflectionUtils.clearCache();
	AnnotationUtils.clearCache();
	ResolvableType.clearCache();
	CachedIntrospectionResults.clearClassLoader(getClassLoader());
}

 

三、Context初始化流程思维导图

至此,以上为代码、注释及说明,简明扼要的用思维导图概括如下图:

 

(本文完)

Spring源码系列【二】——Spring框架概述

1.源码分析前的123
2.Spring框架组件
3.后续思路

一、写在前面的废话

上一篇搭建了 Spring 源码分析的环境,这一篇正式开始了,在进入正题之前先问自己几个问题:

1、为什么要看 Spring 源码?

2、想要分析到哪个层面?

3、如何看 Spring 源码?

……

问题1,不用说了,Spring 框架是众多优秀框架之一,也是 java 从业者必会框架,网上关于 Spring 的赞誉之词不胜枚举,既是用/学一个东西,在用/学之前总要问这个东西为什么会出现?是为了解决哪些问题?研究要有个整体思路,切忌上来就一头扎进代码中,容易“只见树木不见森林”。看源码是为了更深入的了解框架,当出现需求时能抓住切入点,更好的运用、扩展框架。

问题2,Spring 框架十多个组件,在这里并不对所有组件都详细了解,如果确实有需要钻研的当然就另说了,本人这轮打算重点了解常用几个组件实现,以及知道每个组件用于实现哪一类功能就 OK 了。希望做到“每有会意便欣然忘食”,常学常新。

问题3,目前个人功力不够,大局观有限,先抽丝剥茧地一点点看了,在看的过程中会不断更新这部分。

在阅读源码的过程中只需要关心核心的主流程,了解其工作原理,并在阅读的过程中感受它的代码风格以及设计理念就好了,如果真的追求理解每一行代码真的是非常耗时的一件事,毕竟阅读源码的目的大多数是成长而不是真的要去维护 Spring。

网上资料千千万,同一个东西每个人都有不同的见解,总结的一个比一个精彩。但是,古语云:纸上得来终觉浅,绝知此事要躬行。亲自下手带有目的性的研究印象更深、效果更好些。废话不多说了。

二、Spring 组件

2.1 spring-framework 代码

2.2 Spring 框架组件

上图是 Spring4.x 的文档,目前5.x版本中的 Portlet 组件已经被废弃掉了,同时增加了用于异步响应式处理的 WebFlux 组件。红框框住的是比较重要的组件:

Core 组件是 Spring 所有组件的核心;

Bean 组件和 Context 组件是实现 IoC依赖注入的基础;

AOP 组件用于实现切面编程;

Web 组件包括 SpringMVC,是 Web 服务的控制层实现。

三、后续思路

简单说 Spring 就 IoC、AOP,而 Context 和 Bean 又是实现 IoC 和 依赖注入的基础,所以在接下来的代码分析中也将围绕这几个重要的组件进行梳理,并从 Context 说起……

(本文完)

Spring源码系列【一】——调试环境搭建

1.获取仓库地址
2.配置Gradle
3.IDEA检出代码

一、操作环境

Win10,Jdk1.8,IDEA 2019,spring-framework Version 5.2.3

二、获取仓库地址

2.1 Spring 官方源码

源码下载地址:https://github.com/xiguanchendian/spring-framework

GitHub下载代码速度巨慢,此时有个曲线救国的骚操作:在“码云”新建仓库,导入GitHub已有仓库,然后从gitee检出效率就高多了。

我的仓库地址传送门:https://gitee.com/liangyadong/spring-framework

 

2.2 Spring 官方文档

Spring Projects:https://spring.io/docs/reference

Spring Framework :https://docs.spring.io/spring/docs/5.2.3.BUILD-SNAPSHOT/spring-framework-reference/

三、Gradle配置

3.1 下载Gradle5.6.4

官方地址:https://gradle.org/releases/

下载complete版,130M左右,解压到指定目录。

3.2 配置Gradle环境变量

比如我的:E:\Develop\gradle-5.6.4\bin添加到系统环境变量,通过命令 gradle -v 验证,出现以下信息证明已经配置成功了:

这里提一下,我开始下载的是Gradle6.0.1,结果检出代码后build时报版本不匹配问题。需要降一下gradle的版本。报错信息:

The build scan plugin is not compatible with Gradle 6.0 and later.
Please use the Gradle Enterprise plugin instead.

关于版本的问题据说还要考虑IDEA版本,心里有数就行,避免踩坑,实在不行IDEA配置gradle时先选择 Use default Gradle wrapper (recommended) 。

四、IDEA检出代码

“码云”添加本机的SSH公钥,和GitHub操作一样,不赘述了。

代码检出路径就是上面的传送门。

IDEA中gradle配置:

检出完毕截图:

 

五、运行示例

打开 IDEA Terminal ,输入如下命令,预编译 spring-oxm 项目:

gradle g-oxm:compileTestJava

结果如下:

Microsoft Windows [版本 10.0.17134.984]
(c) 2018 Microsoft Corporation。保留所有权利。

F:\IDEA\spring-framework>gradle :spring-oxm:compileTestJava

BUILD SUCCESSFUL in 5s
39 actionable tasks: 39 up-to-date
F:\IDEA\spring-framework>

5.1 解析 XML 配置文件成对应的 BeanDefinitions 的流程

可调试 org.springframework.beans.factory.xml.XmlBeanDefinitionReaderTests 的 withFreshInputStream() 和 withImport() 这两个单元测试,相比来说,后者比前者多了一个 <import /> 标签的解析。

这里只执行一次 withImport() 方法,验证环境有没有问题:

OK,环境搭建好,开始懵逼这么多模块从哪下手看呢?下一篇开始真正的 Spring 源码分析。

 

(本文完)