文档章节

Spring源码阅读-ApplicationContext

Small-Liu
 Small-Liu
发布于 2017/01/22 14:32
字数 2262
阅读 250
收藏 0

ApplicationContext  vs   BeanFactory

beanFactory就是一个容器,它的工作就是实例化、依赖注入,但是仅仅只是这样用户使用比较麻烦,很多事还需要自己做,比如通过Resource加载配置、注册扩展点、添加监听器等等,所以spring提供了一些常用的应用上下文ApplicationContext来帮助用户快速开发,ApplicationContext在beanFactory的基础之上做了扩展,它包含beanFactory的所有功能,并初始化了很多默认功能。

AbstractApplicationContext

ApplicationContext也有很多实现类,这里选取一个常用的ClassPathXmlApplicationContext做测试,跟踪他的构造方法:

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
		throws BeansException {

	super(parent);
	setConfigLocations(configLocations);
	if (refresh) {
		refresh();
	}
}

设置好配置配置文件路径后就进入到refresh方法中,这个refresh方法是在上层抽象类AbstractApplicationContext中,先看一下refresh整体流程:

public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		// 准备上下文
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
		// 读取配置文件初始化beanFactory(加载bean, loadBeanDefinitions)
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		// 上面BeanFactory加载完毕,下面开始ApplicationContext的扩展
		//额外填充beanFactory
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			// 给子类覆盖用的,子类可以对BeanFactory做一些处理
			postProcessBeanFactory(beanFactory);

			// Invoke factory processors registered as beans in the context.
			//执行BeanFactoryPostProcessor
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			//扩展点BeanPostProcessor的注册,在BeanFactory getBean的时候会调用
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			// 初始化message源, 国际化处理
			initMessageSource();

			// Initialize event multicaster for this context.
			// 注册applicationEventMulticaster
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context
			// subclasses.
			onRefresh();//留给子类初始化

			// Check for listener beans and register them.
			//注册监听器
			registerListeners();

			// Instantiate all remaining (non-lazy-init) singletons.
			//实例化对象,对于那些非懒加载的单例
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			//收尾
			finishRefresh();
		}
		catch (BeansException ex) {
			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;
		}
	}
}

这块代码流程一看就比较清晰,依次看每块实现逻辑:

prepareRefresh

protected void prepareRefresh() {
	this.startupDate = System.currentTimeMillis();
	//状态标识
	synchronized (this.activeMonitor) {
		this.active = true;
	}
	if (logger.isInfoEnabled()) {
		logger.info("Refreshing " + this);
	}
	// Initialize any placeholder property sources in the context environment
	//留给子类实现的
	initPropertySources();

	// Validate that all properties marked as required are resolvable
	// see ConfigurablePropertyResolver#setRequiredProperties
	//验证
	getEnvironment().validateRequiredProperties();
}

初始化之前的准备,这个方法很简单,设置标志,准备初始化参数,验证必要的参数,initPropertySources留给子类扩展的。

obtainFreshBeanFactory

这步就是获取beanFactory,这个操作委托给了refreshBeanFactory方法,继续看代码:

protected final void refreshBeanFactory() throws BeansException {
	if (hasBeanFactory()) {
		destroyBeans();
		closeBeanFactory();
	}
	try {
		DefaultListableBeanFactory beanFactory = createBeanFactory();
		beanFactory.setSerializationId(getId());
		//根据当前context的特点对其内部的beanFactory设置属性
		customizeBeanFactory(beanFactory);
		// 这个里面就是通过XmlBeanDefinitionReader加载配置到beanFactory中
		loadBeanDefinitions(beanFactory);
		synchronized (this.beanFactoryMonitor) {
			this.beanFactory = beanFactory;
		}
	} catch (IOException ex) {
		throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(),
				ex);
	}
}

先关闭之前的beanFactory,再创建新的,并根据当前上下文特点对beanFactory设置一些初始化特性参数,然后加载bean的配置。

customizeBeanFactory方法中设置参数,这里主要包括两个参数:    allowBeanDefinitionOverriding允许bean名称重复,后面的覆盖前面的,默认开启、关闭后遇到相同的beanName直接抛异常,allowCircularReferences设置允许循环引用

loadBeanDefinitions方法里面用BeanDefinitionReader读取配置解析加载到beanFactory的BeanDefinitions中,这里就是beanFactory的启动了,从这里也可以看出ApplicationContext做的事情要比 beanFactory多。

prepareBeanFactory

这步就是根据当前应用上下文ApplicationContext配置它内部beanFactory的特色,具体特色还是看代码:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// Tell the internal bean factory to use the context's class loader etc.
	beanFactory.setBeanClassLoader(getClassLoader());
	//el表达式 #{}
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver());
	//属性转换器
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

	// Configure the bean factory with context callbacks.
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	
	//autowireByName autowireByType忽略?
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

	// BeanFactory interface not registered as resolvable type in a plain factory.
	// MessageSource registered (and found for autowiring) as a bean.
	//这些不作为可解析的类型,直接把对应的注入value放到集合中
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);

	// Detect a LoadTimeWeaver and prepare for weaving, if found.
	// AspectJ
	//一个内置扩展点, 主要用于注入LoadTimeWeaver
	if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		// Set a temporary ClassLoader for type matching.
		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. ClassLoader:使用自己的类加载器
  2. BeanExpressionResolver:el表达式解析器,配置中使用#{xxx}
  3. ResourceEditorRegistrar: 属性转换器,比如定义属性为Date,配置文件中配置成字符串,就是通过这个里面的功能把它转换过来的,spring内置了很多属性编辑器。
  4. Aware-processors:对实现了对象的Aware接口注入,如:EnvironmentAware、ApplicationEventPublisherAware、ApplicationContextAware等等。
  5. ignoreDependencyInterface:忽略依赖注入的接口,这步跟第4步是对应的,上面处理了这里就忽略,默认只有BeanFactoryAware,可以调用该方法往忽略集合里面添加。
  6. registerResolvableDependency:如果注入的时候遇到这些类型,不去解析他们而是直接取对应固定的value值
  7. LoadTimeWeaverAwareProcessor: 设置扩展点,如果过bean实现LoadTimeWeaverAware接口,则LoadTimeWeaver对象注入到bean中,LoadTimeWeaver这里涉及到aop相关的概念(spring中实现aop用了好几种方式)
  8. 注册默认环境bean: environment、systemProperties、systemEnvironment

postProcessBeanFactory

上面是spring根据当前ApplicationContext做了很多设定,如果用户自定义ApplicationContext可以重写postProcessBeanFactory做其他设置,这里默认实现为空就是留给子类实现的。

invokeBeanFactoryPostProcessors

执行BeanFactoryPostProcessor,这个也是spring的开闭原则,必须在bean实例化之前执行,BeanFactoryPostProcessor的方法postProcessBeanFactory参数是beanFactory,这些后处理器可以对beanFactory进行修改,所以bean实例化之后再做这边就没有意义了。

registerBeanPostProcessors

扩展点BeanPostProcessor的注册,在BeanFactory getBean的时候会调用

initMessageSource

常用作国际化,spring里面处处都是bean,这里也一样,定义一个MessageSource的bean,在用到该功能的时候获取该bean。

initApplicationEventMulticaster

初始化event multicaster,广播所有事件到所有注册的监听器,让它们自己忽略不感兴趣的事件,默认实现类为SimpleApplicationEventMulticaster,它里面会让所有监听器在当前线程执行,这就有可能某个监听器阻塞整个应用,所有第二种方式是可以指定一个任务执行线程池来执行这些监听器。

onRefresh

留给子类实现,对于指定的bean可以进行特殊初始化

registerListeners

注册监听器到EventMulticaster中,用于接收EventMulticaster的消息,所有实现了ApplicationListener接口的都算,并且不需要提前初始化,

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 lisName : listenerBeanNames) {
		getApplicationEventMulticaster().addApplicationListenerBean(lisName);
	}
}

finishBeanFactoryInitialization

在上下文中bean工厂初始化好了之后对里面必要的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));
	}

	// 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.
	//冻结配置,不允许在修改了
	beanFactory.freezeConfiguration();

	// Instantiate all remaining (non-lazy-init) singletons.
	// 根据条件(非静态、单例、非懒加载)遍历所有beanName实例化
	beanFactory.preInstantiateSingletons();
}

这里最先初始化了类型转换服务,这个服务在后面getBean的时候需要用到类型转换,所以放在第一位,第二位初始化的是实现了LoadTimeWeaverAware的bean,这个里面涉及的比较多,要后面专门开篇,最后实例化满足非静态、单例、非懒加载三个条件的bean。

finishRefresh

protected void finishRefresh() {
	// Initialize lifecycle processor for this context.
	// 初始化lifecycle processor , 默认DefaultLifecycleProcessor
	initLifecycleProcessor();

	// Propagate refresh to lifecycle processor first.
	// 
	getLifecycleProcessor().onRefresh();

	// Publish the final event.
	publishEvent(new ContextRefreshedEvent(this));

	// Participate in LiveBeansView MBean, if active.
	LiveBeansView.registerApplicationContext(this);
}

最后完成ApplicationContext初始化后要初始化一下生命周期处理类,默认DefaultLifecycleProcessor,然后调用它的onRefresh,这里引出另外一个概念:生命周期,spring中Lifecycle接口为生命周期接口,bean只要实现这个接口,在ApplicationContext初始化、销毁后会收到对应的通知,这也是ApplicationContext跟业务bean交互的一种方式。

最后发布上下文启动完毕的通知。

异常结束

如果在初始化的过程中出现了异常,spring会捕获该异常,并把已经创建的单例对象销毁,重置启动状态标志位

总结

spring中以BeanFactory为核心,它的里面处处都是以bean的形式存在,比如国际化资源,事件广播器,生命周期处理器等等都是以bean的形式注册在beanFactory上的,在该核心的基础之上封装了好几种应用上下文,用户通常是通过应用上下文的方式使用。

© 著作权归作者所有

Small-Liu
粉丝 17
博文 56
码字总数 49976
作品 0
南京
程序员
私信 提问
向Spring大佬低头——大量源码流出解析

用Spring框架做了几年的开发,只停留在会用的阶段上,然而Spring的设计思想和原理确实一个巨大的宝库。大部分人仅仅知道怎么去配,或着加上什么属性就能达到什么效果,这些东西都可以通过查文...

Java团长17
2018/07/11
0
0
Spring IOC 容器源码分析(一)

Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器。既然大家平时都要用到 Spring,怎么可以不好好了解 Spring 呢?阅读本文并不能让你成为 Spring...

小码哥的freestyle
04/05
0
0
请别再问Spring Bean的生命周期了!

Spring Bean的生命周期是Spring面试热点问题。这个问题即考察对Spring的微观了解,又考察对Spring的宏观认识,想要答好并不容易!本文希望能够从源码角度入手,帮助面试者彻底搞定Spring Be...

sunshujie1990
05/30
0
0
给spring-boot测试提供unitils支持的开源项目

一、unitils测试框架优缺点介绍 在unitils的支持下,xml配置的spring项目在测试时,有如下好处: 1、利用注解@DataSet、@ExpectedDataSet来准备数据和校验结果数据,每次运行测试用例不用重新...

yangjianzhou
2018/07/09
489
1
Spring Boot 运作原理

1、Spring Boot 简介 SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义...

编程SHA
02/22
187
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周四乱弹 —— 当你简历注水但还是找到了工作

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @花间小酌 :#今日歌曲推荐# 分享成龙的单曲《男儿当自强》。 《男儿当自强》- 成龙 手机党少年们想听歌,请使劲儿戳(这里) @hxg2016 :刚在...

小小编辑
今天
2.7K
22
靠写代码赚钱的一些门路

作者 @mezod 译者 @josephchang10 如今,通过自己的代码去赚钱变得越来越简单,不过对很多人来说依然还是很难,因为他们不知道有哪些门路。 今天给大家分享一个精彩的 GitHub 库,这个库整理...

高级农民工
昨天
3
0
用好项目管理工具,人人都可以成为项目经理

现在市面上的项目管理工具越来越多了,但是大多数都是一些协同工具或轻量项目管理工具。如果是多团队、跨部门使用或者企业级的项目管理,从管理思想到工具运用,需要适应企业的业务流程体系,...

cs平台
昨天
12
0
只需一步,在Spring Boot中统一Restful API返回值格式与统一处理异常

统一返回值 在前后端分离大行其道的今天,有一个统一的返回值格式不仅能使我们的接口看起来更漂亮,而且还可以使前端可以统一处理很多东西,避免很多问题的产生。 比较通用的返回值格式如下:...

晓月寒丶
昨天
69
0
区块链应用到供应链上的好处和实际案例

区块链可以解决供应链中的很多问题,例如记录以及追踪产品。那么使用区块链应用到各产品供应链上到底有什么好处?猎头悬赏平台解优人才网小编给大家做个简单的分享: 使用区块链的最突出的优...

猎头悬赏平台
昨天
32
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部