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

2020年1月7日12:50:20 发表评论 50
摘要

Context 初始化流程

Context 也即是常说的上下文,个人理解是程序执行的环境、一个容器,其初始化流程分12步(12个方法),也可以说是13步(外加 finally 代码块执行的那个方法)。

为便于查看每个方法的功能描述,后面我会用散装英语“翻译”一下,注释是在原英文注释下面。

一、Context 初始化流程(12个方法)

入口代码:AbstractApplicationContext.java#refresh() 方法:

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		// 1.准备此上下文以进行刷新,即刷新前上下文环境准备
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
		// 2.告诉子类刷新内部bean工厂
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		// 3.准备在上下文中使用的bean工厂
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			// 4.允许在上下文子类中对bean工厂进行后处理
			postProcessBeanFactory(beanFactory);

			// Invoke factory processors registered as beans in the context.
			// 5.调用在上下文中注册为bean的工厂处理器
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			// 6.注册拦截bean创建的bean处理器,即注册BeanPostProcessors
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			// 7.为此上下文初始化消息源
			initMessageSource();

			// Initialize event multicaster for this context.
			// 8.为此上下文初始化事件多播器(广播器?)
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			// 9.在特定上下文子类中初始化其他特殊bean
			onRefresh();

			// Check for listener beans and register them.
			// 10.检查监听器bean并注册它们
			registerListeners();

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

			// Last step: publish corresponding event.
			// 12.最后一步:发布相应事件
			finishRefresh();
		}

		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}

			// Destroy already created singletons to avoid dangling resources.
			// 销毁已创建的单例以避免资源悬空
			destroyBeans();

			// Reset 'active' flag.
			// 重置活动标识
			cancelRefresh(ex);

			// Propagate exception to caller.
			// 将异常抛给调用者
			throw ex;
		}

		finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			// 13.重置spring核心中常见的内省缓存,因为我们可能不再需要单例bean的元数据...
			resetCommonCaches();
		}
	}
}

二、方法详解

使用IDEA时,ctrl+alt+B 和 ctrl+shift+R 以及 ctrl+alt+←(→) 是很常用的跟踪代码的快捷键。

2.1 #prepareRefresh()

对 refresh 做准备,包括设置开始时间、设置激活状态、初始化 Context 环境中的占位符,这个动作根据子类的需求由子类来执行,然后验证是否缺失必要的 properties。

/**
 * Prepare this context for refreshing, setting its startup date and
 * active flag as well as performing any initialization of property sources.
 * 刷新上下文准备,设置启动时间和活动标识,以及执行属性源的任何初始化
 */
protected void prepareRefresh() {
	// Switch to active.
	// 切换到活动状态
	this.startupDate = System.currentTimeMillis();
	this.closed.set(false);
	this.active.set(true);

	if (logger.isDebugEnabled()) {
		if (logger.isTraceEnabled()) {
			logger.trace("Refreshing " + this);
		}
		else {
			logger.debug("Refreshing " + getDisplayName());
		}
	}

	// Initialize any placeholder property sources in the context environment.
	// 在上下文环境中初始化任何占位符属性源
	initPropertySources();

	// Validate that all properties marked as required are resolvable:
	// see ConfigurablePropertyResolver#setRequiredProperties
	// 验证所有标记为必需的属性都是可解析的
	// 参见ConfigurablePropertyResolver#setRequiredProperties
	getEnvironment().validateRequiredProperties();

	// Store pre-refresh ApplicationListeners...
	// 存储预刷新的ApplicationListeners
	if (this.earlyApplicationListeners == null) {
		this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
	}
	else {
		// Reset local application listeners to pre-refresh state.
		// 将本地程序监听器重置为预刷新状态
		this.applicationListeners.clear();
		this.applicationListeners.addAll(this.earlyApplicationListeners);
	}

	// Allow for the collection of early ApplicationEvents,
	// to be published once the multicaster is available...
	// 允许收集早期的ApplicationEvents,一旦多播器可用就将其发布
	this.earlyApplicationEvents = new LinkedHashSet<>();
}

关注 initPropertySources()getEnvironment().validateRequiredProperties()。initPropertySources() 方法内为空,这是 Spring 开放式架构设计,给用户扩展 Spring 的能力,也就是留给子类覆盖,当业务上有参数验证需求的时候,可以通过自定义类继承 ClassPathXMLApplicationContext 重写该方法,将参数验证逻辑写入方法内,并且在使用的时候替换原有的 ClassPathXMLApplicationContext。

2.2 #obtainFreshBeanFactory()

refresh 并获得内部的 Bean Factory。这方法名起的真有水平。

/**
 * Tell the subclass to refresh the internal bean factory.
 * @return the fresh BeanFactory instance
 * @see #refreshBeanFactory()
 * @see #getBeanFactory()
 */
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	refreshBeanFactory();
	return getBeanFactory();
}

其中 refreshBeanFactory() 方法:

/**
 * This implementation performs an actual refresh of this context's underlying
 * bean factory, shutting down the previous bean factory (if any) and
 * initializing a fresh bean factory for the next phase of the context's lifecycle.
 * 该实现会实际刷新此上下文的基础Bean工厂,关闭前一个Bean工厂(如果有)
 * 并为上下文的生命周期的下一个阶段初始化一个新的Bean工厂
 */
@Override
protected final void refreshBeanFactory() throws BeansException {
	if (hasBeanFactory()) {
		destroyBeans();
		closeBeanFactory();
	}
	try {
		// 1.为此上下文创建一个内部bean工厂
		DefaultListableBeanFactory beanFactory = createBeanFactory();
		// 2.指定一个ID以进行序列化,如果需要的话,允许将该BeanFactory从该ID反序列化回BeanFactory对象
		beanFactory.setSerializationId(getId());
		// 3.定制此上下文使用的内部bean工厂
		customizeBeanFactory(beanFactory);
		// 4.将bean定义加载到给定的bean工厂中
		loadBeanDefinitions(beanFactory);
		// 5.设置Context的beanFactory
		synchronized (this.beanFactoryMonitor) {
			this.beanFactory = beanFactory;
		}
	}
	catch (IOException ex) {
		throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
	}
}

关注 customizeBeanFactory(beanFactory) loadBeanDefinitions(beanFactory)

customizeBeanFactory(beanFactory) 定制beanFactory,设置相关属性,包括是否允许同名称的不同定义的对象以及是否允许 bean 之间存在循环依赖。

loadBeanDefinitions(beanFactory) 初始化 XmlBeanDefinitionReader ,设置环境变量(environment、resourceLoader、entityResolver)。在初始化 DefaultListableBeanFactory 和 XmlBeanDefinitionReader 后就可以进行配置文件的读取了。

2.3 #prepareBeanFactory()

对 BeanFactory 进行准备工作,比如设置类加载器和后置处理器,配置不进行自动装配的类型、注册默认的环境 Bean。

/**
 * Configure the factory's standard context characteristics,
 * such as the context's ClassLoader and post-processors.
 * 配置工厂的标准上下文特征,例如上下文的类加载器和后置处理器
 * @param beanFactory the BeanFactory to configure
 */
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// Tell the internal bean factory to use the context's class loader etc.
	// 告诉内部bean工厂使用上下文的类加载器等
	beanFactory.setBeanClassLoader(getClassLoader());
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

	// Configure the bean factory with context callbacks.
	// 使用上下文回调配置bean工厂
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
	beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

	// BeanFactory interface not registered as resolvable type in a plain factory.
	// MessageSource registered (and found for autowiring) as a bean
	// BeanFactory接口未在普通工厂中注册为可解析类型
	// MessageSource注册为bean(并发现用于自动装配)
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);

	// Register early post-processor for detecting inner beans as ApplicationListeners.
	// 注册早期的后置处理器以将内部bean检测为ApplicationListeners
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

	// Detect a LoadTimeWeaver and prepare for weaving, if found.
	// 如果发现LoadTimeWeaver准备编制
	if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		// Set a temporary ClassLoader for type matching.
		// 设置一个临时的ClassLoader以进行类型匹配
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}

	// Register default environment beans.
	// 注册默认环境bean
	if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
	}
	if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
	}
	if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
	}
}

以上方法主要进行了几个方面的功能扩展:

  • 1. 增加对SpEL语言的支持

SpEL全称 Spring Expression Language,类似于 Struts2 中的 OGNL 表达式,能在运行时构建复杂表达式、存取对象属性、对象方法调用等,并且能与 Spring 功能完美整合,比如能用来配置 bean 定义。SpEL 是单独模块,只依赖于 core 模块,不依赖其他模块,可以单独使用。比如 value=“#{mobilephone}” 的解析。详细可以看 AbstractBeanFactory 中 #evaluateBeanDefinitionString() 方法,查看该方法的调用层次可以看出应用语言解析器的调用主要是在解析依赖注入 bean 的时候,以及在完成 bean 的初始化和属性获取后进行属性填充的时候。

  • 2. 增加对属性编辑器的支持

在 Spring DI 注入的时候可以把普通属性注入进来,但是像 Date 类型就无法被识别,针对类型转换不成功程序抛异常的处理,Spring 提供了两种解决办法:

使用自定义属性编辑器(通过继承 PropertyEditorSupport,重写 setAsText 方法,自定义属性编辑器)和注册 Spring 自带的属性编辑器 CustomDateEditor,此处不作扩展了。

  • 3. 增加对一些内置类,比如 EnvironmentAware、MessageSourceAware的信息注入

添加 ApplicationContextAwareProcessor 处理器。

  • 4. 设置了依赖功能可忽略的接口

当 Spring 将 ApplicationContextAwareProcessor 注册后,那么在 invokeAwareInterfaces 方法中间接调用的 Aware 类已经不是普通的 bean 了,需要在 Spring 做 bean 的依赖注入的时候忽略它们。

  • 5. 注册一些固定依赖的属性

当注册了依赖解析后,例如当注册了对 BeanFactory.class 的解析依赖后,当 bean 的属性注入的时候,一旦检测到属性为 BeanFactory 类型便会将 beanFactory 的实例注入进去。

  • 6. 增加 AspectJ 的支持
  • 7. 将相关环境变量及属性注册以单例模式注册

2.4 #postProcessBeanFactory()

为 Context 的子类提供后置处理 BeanFactory 的扩展能力,如果子类想在 Bean 定义加载完成后、开始初始化上下文之前做一些特殊处理,可以复写这个方法。

/**
 * Register request/session scopes, a {@link ServletContextAwareProcessor}, etc.
 */
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// 1.添加ServletContextAwareProcessor到BeanFactory中,该processor实现BeanPostProcessor接口,主要用于将ServletContext传递给实现了ServletContextAware接口的bean
	beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
	// 2.忽略ServletContextAware和ServletConfigAware
	beanFactory.ignoreDependencyInterface(ServletContextAware.class);
	beanFactory.ignoreDependencyInterface(ServletConfigAware.class);

	// 3.注册特定于web的作用域例如"request", "session", "globalSession", "application"到给定的BeanFactory中,由Web应用程序上下文使用
	WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
	// 4.注册特定于web环境的bean例如"contextParameters", "contextAttributes"到给定的BeanFactory中,由Web应用程序上下文使用
	WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}

 

2.5 #invokeBeanFactoryPostProcessors()

调用Context 中注册的 BeanFactory 后置处理器。这里有两种后置处理器,一种是可以注册 Bean 的后置处理器,另一种是针对 BeanFactory 进行处理的后置处理器。执行顺序是先按优先级执行可注册 Bean 的处理器,再按优先级执行针对 BeanFactory 的处理器。

对 Spring Boot 来说,这一步会进行注解 Bean Definition 的解析。流程:由 ConfigurationClassPostProcessor 触发、由 ClassPathBeanDefinitionScanner 解析并注册到 BeanFactory。

/**
 * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
 * respecting explicit order if given.
 * <p>Must be called before singleton instantiation.
 * 实例化并调用所有已注册的BeanFactoryPostProcessor bean,遵守明确的命令(如果有)
 * 必须在单例实例化之前调用
 */
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

	// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
	// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
	// 检测LoadTimeWeaver并准备编织(如果在此期间发现)
	// 例如通过ConfigurationClassPostProcessor注册的@Bean方法
	if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}
}

 

2.6 #registerBeanPostProcessors()

按优先级顺序在 BeanFactory 中注册 Bean 的后置处理器,Bean 后置处理器可以在 Bean 初始化前、后执行处理。

/**
 * Instantiate and register all BeanPostProcessor beans,
 * respecting explicit order if given.
 * <p>Must be called before any instantiation of application beans.
 * 实例化并注册所有BeanPostProcessor bean,遵守明确的命令(如果有)
 * 必须在应用程序bean的任何实例化之前调用
 */
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

其中,PostProcessorRegistrationDelegate.java #registerBeanPostProcessors()方法:

public static void registerBeanPostProcessors(
		ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

	// Register BeanPostProcessorChecker that logs an info message when
	// a bean is created during BeanPostProcessor instantiation, i.e. when
	// a bean is not eligible for getting processed by all BeanPostProcessors.
	int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
	beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

	// Separate between BeanPostProcessors that implement PriorityOrdered,
	// Ordered, and the rest.
	List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
	List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
	List<String> orderedPostProcessorNames = new ArrayList<>();
	List<String> nonOrderedPostProcessorNames = new ArrayList<>();
	for (String ppName : postProcessorNames) {
		if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			priorityOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			orderedPostProcessorNames.add(ppName);
		}
		else {
			nonOrderedPostProcessorNames.add(ppName);
		}
	}

	// First, register the BeanPostProcessors that implement PriorityOrdered.
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

	// Next, register the BeanPostProcessors that implement Ordered.
	List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
	for (String ppName : orderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		orderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	sortPostProcessors(orderedPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, orderedPostProcessors);

	// Now, register all regular BeanPostProcessors.
	List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
	for (String ppName : nonOrderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		nonOrderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

	// Finally, re-register all internal BeanPostProcessors.
	sortPostProcessors(internalPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, internalPostProcessors);

	// Re-register post-processor for detecting inner beans as ApplicationListeners,
	// moving it to the end of the processor chain (for picking up proxies etc).
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

 

(本文未完待续,接下一篇)

  • 我的微信
  • 微信扫一扫
  • weinxin
  • 微信公众号
  • 微信公众号(习惯沉淀)
  • weinxin

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: