Spring源码之IOC(五)ApplicationContext源码分析

1 概述

ApplicationContext即应用上下文,它是建立在BeanFactory基础之上的 ApplicationContext有两个主要的实现类:ClassPathXmlApplicationContext:默认从类路径加载配置文件,还有FileSystemXmlApplicationContext:默认从文件系统中装载配置文件,
通常我们使用的比较多的是ClassPathXmlApplicationContext。

2 继承关系

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
... ...

(1)EnvironmentCapable:提供获取环境对象(Environment)功能的接口。
(2)ListableBeanFactory, HierarchicalBeanFactory:这两个都是BeanFactory的实现类,可以看出ApplicationContext扩展了BeanFactory的功能。
(3)MessageSource:提供国际化消息访问的功能。
(4)ApplicationEventPublisher:该接口让容器拥有发布应用上下文事件的功能,例如容器启动和容器关闭等。
(4)ResourcePatternResolver:装载配置文件进入Resource对象。

3 函数

(1)String getId();
返回应用上下文唯一的id。
(2)String getApplicationName();
返回此上下文所属的已部署应用程序的名称。
(3)String getDisplayName();
返回此上下文一个友好的名称。
(4)long getStartupDate();
返回此上下文第一次加载的日期。
(5)ApplicationContext getParent();
返回父上下文,如果没有就为空。
(7)AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
为这个上下文公开autowiablebeanfactory功能。

4 子类

在这里针对这个接口的子类,我们仅仅分析部分的实现和作用。

4.1 ConfigurableApplicationContext

这个接口将由大多数应用程序上下文实现。除了ApplicationContext接口的功能之外,还提供了配置应用上下文的功能。
这个接口继承了Lifecycle接口,Lifecycle接口是定义用于启动/停止生命周期控制的方法的公共接口,通常针对异步处理比较常用。

4.2 AbstractApplicationContext

ApplicationContext接口的抽象实现,简单地实现了公共上下文功能。这个类的设计使用了模板方法的设计模式,具体的实现由子类来实现。

4.2.1 继承关系

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext

(1)DefaultResourceLoader

ResourceLoader接口的默认实现,被ResourceEditor类使用 。

这里我们来看一下此类的getResource函数。

@Override
public Resource getResource(String location) {
	Assert.notNull(location, "Location must not be null");

	//遍历协议特定资源句柄的解决策略,如果有资源location的匹配策略,则直接返回
	for (ProtocolResolver protocolResolver : this.protocolResolvers) {
		Resource resource = protocolResolver.resolve(location, this);
		
		//获得配置文件资源
		if (resource != null) {
			return resource;
		}
	}

	//通过路径获取资源(相对路径)
	if (location.startsWith("/")) {
		return getResourceByPath(location);
	}
	
	//类路径
	else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
		return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
	}
	else {
		try {
			URL url = new URL(location);
			return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
		}
		catch (MalformedURLException ex) {
			return getResourceByPath(location);
		}
	}
}

这个函数的作用其实就是获取资源的Resource对象。支持全路径,classpath类路径和文件的相对路径几种方式。

4.2.2 函数

针对这个类,我们来分析一下refresh函数。
refresh函数的作用是加载或者刷新配置的持久化表示。
源码如下:

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			
			//准备刷新上下文
			prepareRefresh();

			//告述子类刷新内部bean工厂
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			//准备在此上下文中使用的Bean工厂
			prepareBeanFactory(beanFactory);

			try {
				//允许在上下文子类中对bean工厂进行后处理,当前此类中对这个函数没有任何实现内容。
				postProcessBeanFactory(beanFactory);

				//调用在上下文中注册为bean的工厂处理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				//初始化上下文的消息资源
				initMessageSource();

				//初始化容器的事件多播器
				initApplicationEventMulticaster();

				//初始化特定上下文子类中的其他特殊bean。此函数当前实现为空
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				//完成容器刷新.
				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...
				resetCommonCaches();
			}
		}
	}

prepareRefresh()函数:

这个函数的作用是为刷新做好上下文准备,包括设置她的开始时间、激活状态和执行任何属性资源的初始化。
具体的源码如下:

protected void prepareRefresh() {
		this.startupDate = System.currentTimeMillis();
		this.closed.set(false);
		this.active.set(true);

		if (logger.isInfoEnabled()) {
			logger.info("Refreshing " + this);
		}

		//初始化上下文环境的任何属性资源,这个函数的具体实现被延迟到了子类,默认情况下什么也不做
		initPropertySources();

		//检测每个属性是否是存在并且非空的
		getEnvironment().validateRequiredProperties();

		this.earlyApplicationEvents = new LinkedHashSet<>();
}

obtainFreshBeanFactory函数:

这个函数的作用是告述子类刷新内部bean工厂。
具体源码如下:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {

        //这是一个抽象函数,子类必须实现它,这个也就是模板方法模式中的基本方法。
	refreshBeanFactory();
		
	//这也是一个抽象函数,子类必须实现它。子类必须但会内部bean工厂。
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	if (logger.isDebugEnabled()) {
		logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
	}
	return beanFactory;
}

prepareBeanFactory函数:

这个函数的作用是配置工厂标准的上下文属性,例如上下文的类加载器和后处理器。
具体源码如下:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	//告诉内部bean工厂使用上下文的类加载器等
	beanFactory.setBeanClassLoader(getClassLoader());
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

	//使用上下文回调配置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接口没有注册为可解析类型。
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);

	//注册早期的后处理器,以便将内部bean检测为applicationlistener。
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

	// Detect a LoadTimeWeaver and prepare for weaving, if found.
	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()));
	}

	//注册默认的环境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());
	}
}

invokeBeanFactoryPostProcessors函数:

调用在上下文中注册为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)
	if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}
}

initMessageSource函数:

初始化容器的消息资源,如果当前上下文的为空则使用父上下文的。
源码如下:

protected void initMessageSource() {

        //获取工厂bean
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		
		//bean工厂中包含messageResource bean
		if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
			this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
			
			//设置message resource的父message resource
			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.
					hms.setParentMessageSource(getInternalParentMessageSource());
				}
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Using MessageSource [" + this.messageSource + "]");
			}
		}
		//bean工厂中不包含messageResource bean
		else {
			
			//初始化message resource
			DelegatingMessageSource dms = new DelegatingMessageSource();
			dms.setParentMessageSource(getInternalParentMessageSource());
			this.messageSource = dms;
			beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
			if (logger.isDebugEnabled()) {
				logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
						"': using default [" + this.messageSource + "]");
			}
		}
	}

4.3 AbstractRefreshableApplicationContext

ApplicationContext实现的基本类,应该支持对refresh()函数的多次调用。每次创建一个新的bean工厂实例,通常(但不一定),这样的上下文将由一组配置位置驱动,以便从这些配置位置加载bean定义。

4.4 AbstractXmlApplicationContext

这个子类提供从xml文档读取配置和bean定义的功能,这个读取功能通过XmlBeanDefinitionReader实现。

4.4.1 属性

private boolean validating = true;//设置是否需要进行xml校验。

4.4.2 函数

针对这个类,我们来看一下loadBeanDefinitions函数。
这个函数的作用就是通过XmlBeanDefinitionReader来加载bean定义,具体源码如下(针对这个函数的分析此处略显啰嗦,没有优化):

上面的代码,在代码(2)处调用了XmlBeanDefinitionReader的函数loadBeanDefinitions。

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {

        //获取配置资源(1)
	Resource[] configResources = getConfigResources();
	if (configResources != null) {
		
	        //加载bean定义(2)
		reader.loadBeanDefinitions(configResources);
	}
	String[] configLocations = getConfigLocations();
	if (configLocations != null) {
		reader.loadBeanDefinitions(configLocations);
	}
}

 

上面的函数,最终调用如下函数:

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
	return loadBeanDefinitions(new EncodedResource(resource));
}

在这个函数中,调用了public int loadBeanDefinitions(EncodedResource encodedResource)函数,我们可以看见传入了EncodedResource参数,EncodedResource类其实是对Resource,编码和charset的封装。
具体的源码如下:

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
	Assert.notNull(encodedResource, "EncodedResource must not be null");
	if (logger.isInfoEnabled()) {
		logger.info("Loading XML bean definitions from " + encodedResource.getResource());
	}

	Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
	if (currentResources == null) {
		currentResources = new HashSet<>(4);
		this.resourcesCurrentlyBeingLoaded.set(currentResources);
	}
	if (!currentResources.add(encodedResource)) {
		throw new BeanDefinitionStoreException(
				"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
	}
	try {
		InputStream inputStream = encodedResource.getResource().getInputStream();
		try {
			InputSource inputSource = new InputSource(inputStream);
			if (encodedResource.getEncoding() != null) {
				inputSource.setEncoding(encodedResource.getEncoding());
			}
			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
		}
		finally {
			inputStream.close();
		}
	}
	catch (IOException ex) {
		throw new BeanDefinitionStoreException(
				"IOException parsing XML document from " + encodedResource.getResource(), ex);
	}
	finally {
		currentResources.remove(encodedResource);
		if (currentResources.isEmpty()) {
			this.resourcesCurrentlyBeingLoaded.remove();
		}
	}
}

通过上面的代码,我们可以发现获取到inputSource和encodeResource后,调用了doLoadBeanDefinitions函数。
在doLoadBeanDefinitions函数里面生成Document后,调用了registerBeanDefinitions函数。
这个函数的作用其实就是注册包含在被给Document中的bean定义。

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
	int countBefore = getRegistry().getBeanDefinitionCount();
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	return getRegistry().getBeanDefinitionCount() - countBefore;
}

针对上面的代码我们需要详细说明一下。
A、BeanDefinitionDocumentReader类
用于解析包含Spring bean定义的XML文档的SPI。由XmlBeanDefinitionReader进行实际解析DOM文档。
这个接口拥有的函数如下:

void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)            throws BeanDefinitionStoreException;

这个函数的作用就是从xml文档中读取bean定义,并使用readerContext中的注册器对其进行注册。
我们再来看一下这个函数的具体实现干了啥。

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
	this.readerContext = readerContext;
	logger.debug("Loading bean definitions");
	Element root = doc.getDocumentElement();
	doRegisterBeanDefinitions(root);
}

重点是获取到root节点后,调用的最终的doRegisterBeanDefinitions函数。

protected void doRegisterBeanDefinitions(Element root) {
	BeanDefinitionParserDelegate parent = this.delegate;
	this.delegate = createDelegate(getReaderContext(), root, parent);

	if (this.delegate.isDefaultNamespace(root)) {
		String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
		if (StringUtils.hasText(profileSpec)) {
			String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
					profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
				if (logger.isInfoEnabled()) {
					logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
							"] not matching: " + getReaderContext().getResource());
				}
				return;
			}
		}
	}

	preProcessXml(root);
	parseBeanDefinitions(root, this.delegate);
	postProcessXml(root);

	this.delegate = parent;
}

针对这个函数,最终要的其实是调用parseBeanDefinitions函数。

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
	if (delegate.isDefaultNamespace(root)) {
		NodeList nl = root.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (node instanceof Element) {
				Element ele = (Element) node;
				if (delegate.isDefaultNamespace(ele)) {
					parseDefaultElement(ele, delegate);
				}
				else {
					delegate.parseCustomElement(ele);
				}
			}
		}
	}
	else {
		delegate.parseCustomElement(root);
	}
}

上面这个函数最终会调用parseDefaultElement函数,在parseDefaultElement函数中,调用processBeanDefinition函数来完成bean定义的注册。

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

	//将Element转换成BeanDefinitionHolder,这里面包含beanDefinition,beanName,aliases
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	if (bdHolder != null) {
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			//注册bean定义
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" +
					bdHolder.getBeanName() + "'", ele, ex);
		}
		//发起注册事件
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

最终上面的函数会调用到DefaultListableBeanFactory的registerBeanDefinition函数。我们来看一下这个函数。

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
		throws BeanDefinitionStoreException {

	Assert.hasText(beanName, "Bean name must not be empty");
	Assert.notNull(beanDefinition, "BeanDefinition must not be null");

	if (beanDefinition instanceof AbstractBeanDefinition) {
		try {
			((AbstractBeanDefinition) beanDefinition).validate();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
					"Validation of bean definition failed", ex);
		}
	}

	BeanDefinition oldBeanDefinition;

	oldBeanDefinition = this.beanDefinitionMap.get(beanName);
	if (oldBeanDefinition != null) {
		if (!isAllowBeanDefinitionOverriding()) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
					"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
					"': There is already [" + oldBeanDefinition + "] bound.");
		}
		else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
			// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
			if (this.logger.isWarnEnabled()) {
				this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
						"' with a framework-generated bean definition: replacing [" +
						oldBeanDefinition + "] with [" + beanDefinition + "]");
			}
		}
		else if (!beanDefinition.equals(oldBeanDefinition)) {
			if (this.logger.isInfoEnabled()) {
				this.logger.info("Overriding bean definition for bean '" + beanName +
						"' with a different definition: replacing [" + oldBeanDefinition +
						"] with [" + beanDefinition + "]");
			}
		}
		else {
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Overriding bean definition for bean '" + beanName +
						"' with an equivalent definition: replacing [" + oldBeanDefinition +
						"] with [" + beanDefinition + "]");
			}
		}
		this.beanDefinitionMap.put(beanName, beanDefinition);
	}
	else {
		if (hasBeanCreationStarted()) {
			// Cannot modify startup-time collection elements anymore (for stable iteration)
			synchronized (this.beanDefinitionMap) {
				this.beanDefinitionMap.put(beanName, beanDefinition);
				List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
				updatedDefinitions.addAll(this.beanDefinitionNames);
				updatedDefinitions.add(beanName);
				this.beanDefinitionNames = updatedDefinitions;
				if (this.manualSingletonNames.contains(beanName)) {
					Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
					updatedSingletons.remove(beanName);
					this.manualSingletonNames = updatedSingletons;
				}
			}
		}
		else {
			// Still in startup registration phase
			this.beanDefinitionMap.put(beanName, beanDefinition);
			this.beanDefinitionNames.add(beanName);
			this.manualSingletonNames.remove(beanName);
		}
		this.frozenBeanDefinitionNames = null;
	}

	if (oldBeanDefinition != null || containsSingleton(beanName)) {
		resetBeanDefinition(beanName);
	}
}

这个函数的this.beanDefinitionMap.put(beanName, beanDefinition);这一步就完成的beanDefinition的注册。
上面就是对AbstractXmlApplicationContext类的loadBeanDefinitions函数的分析,有点啰嗦,但是最终表明了整个函数bean定义的xml配置文件的解析到bean定义的注册的整个过程。

4.5 ClassPathXmlApplicationContext和FileSystemXmlApplicationContext

这两个类是标准的XML应用上下文,不同的是他们获取容器定义文件的路径,ClassPathXmlApplicationContext从class path获取,而FileSystemXmlApplicationContext是从文件系统或者URL。
上面就是对Spring容器(ApplicationContext)的分析,后面我们将继续分析SpringIOC的源码,欢迎交流。

    原文作者:Spring MVC
    原文地址: https://blog.csdn.net/ONROAD0612/article/details/85101720
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞