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源码系列【三】——Context初始化流程(上)

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));
}

 

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

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 源码分析。

 

(本文完)