Spring源码分析--IOC容器篇

一、环境准备

我们以xml配置文件示例

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <beans>
        <bean id="luoluo" class="com.luo.pojo.Goods">
            <property name="name" value="hehe"/>
        </bean>
    </beans>
</beans>

spring的启动类

public class SpringRun {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
        Object luo = applicationContext.getBean("luoluo");
    }
}

二、知识初探

IOC中设计到的几个很重要的类,如下

接口、类含义
BeanFactory创建bean的顶级接口
BeanDefinitionxml中的bean信息最终会被解析成为一个个BeanDefinition
BeanDefinitionMap<k,v>键值对,key是bean的名称,v 是对应的BeanDefinition

在这里插入图片描述

二、开始走进源码

  1. 先看第一句代码
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("application.xml");

进入该方法

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
}
	
public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
		super(parent);
		setConfigLocations(configLocations); //把配置文件路径设置到上下文中,方便下文解析
		if (refresh) {
			refresh(); //这里是最重要的方法
	}
}

setConfigLocations(configLocations);

把配置文件加载进容器中,那么是怎么加载进容器的呢?在这之前我们先了解下资源加载器 ResourceLoader和资源模式解析器 ResourcePatternResolver,用于从类路径下或者文件系统中加载并识别资源。常见的资源模式如下

  • classpath:
  • classpath*:
  • /WEB-INF/*-context.xml
  • /beans.xml

既然能够加载文件系统中的资源,比如C:\Users\luo20\Desktop\dubbo.xml,那么我们操作系统的环境信息应该在加载配置文件之前就设置进上下文中,这个也有对应的实现

protected String resolvePath(String path) {
		return getEnvironment().resolveRequiredPlaceholders(path);
	}

现在系统的信息也有了,配置文件资源也有了,接下来开始最最最重要的方法

refresh()

这个方法是IOC的核心

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			//记录上下文的启动时间和当前的状态等信息
			prepareRefresh();

			// 将配置文件中的信息提取出来并创建对象,封装为BeanDefinition,然后添加到BeanDefinitionMap
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 配置beanFactory相关信息
			prepareBeanFactory(beanFactory);

			try {
				// 对BeanFactory进行后置处理
				postProcessBeanFactory(beanFactory);

				// 实例化并调用所有的BeanFactoryPostProcessor
				invokeBeanFactoryPostProcessors(beanFactory);

				// 实例化并注册BeanPostProcessor
				registerBeanPostProcessors(beanFactory);

				// 处理国际化
				initMessageSource();

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

				//  模板方法,它可以被重写,用于上下文的刷新工作
				onRefresh();

				//  注册事件监听器,监听器需要实现 ApplicationListener 接口
				registerListeners();

				// 创建并初始化所有剩余的(非lazy-init)单例
				finishBeanFactoryInitialization(beanFactory);

				//广播事件,ApplicationContext 初始化完成
				finishRefresh();
			}
			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}
				destroyBeans();
				cancelRefresh(ex);
				throw ex;
			}
			finally {
				resetCommonCaches();
			}
		}
	}

下面我将一个一个方法进行深入解析

方法一:prepareRefresh();

protected void prepareRefresh() {
		// 设置容器的启动时间、激活状态
		this.startupDate = System.currentTimeMillis(); 
		this.closed.set(false);
		this.active.set(true); 

		// 这是一个空方法
		initPropertySources();
		// 校验需要的配置文件是否可以解析
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh 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...
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

方法二:ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		return getBeanFactory();
	}
@Override
	protected final void refreshBeanFactory() throws BeansException {
		//之前如果有bean工厂,清理掉
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			//新建一个beanFactory 
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			//对beanFactory进行一些定制化
			customizeBeanFactory(beanFactory);
			//从配置文件中加载对象信息,包装为BeanDefinition
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

重点在怎么把xml变为BeanDefinition,进入loadBeanDefinitions(beanFactory);

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
		// 设置需要的环境
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);
		//还没有真正进入到处理的方法,继续进入
		loadBeanDefinitions(beanDefinitionReader);
	}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		//获取配置文件,在之前已经把配置文件设置进了上下文,所以很容易获取
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			//还没有开始处理,进入
			reader.loadBeanDefinitions(configLocations);
		}
	}
@Override
	public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
		Assert.notNull(locations, "Location array must not be null");
		int count = 0;
		for (String location : locations) {
			//还没有开始处理,进入
			count += loadBeanDefinitions(location);
		}
		//返回配置文件的数量
		return count;
	}

经过一系列的loadBeanDefinitions,最终到了这个方法

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

		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()) {
			InputSource inputSource = new InputSource(inputStream);
			if (encodedResource.getEncoding() != null) {
				inputSource.setEncoding(encodedResource.getEncoding());
			}
			//这里我们看到doLoadBeanDefinitions,而不是LoadBeanDefinitions,太好啦
			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}

进入doLoadBeanDefinitions(inputSource, encodedResource.getResource());

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		try {
			//把xml解析成为文档对象,可以进行调试看看doc结果
			Document doc = doLoadDocument(inputSource, resource);
			//生成并注册BeanDefinition
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}

进入registerBeanDefinitions(doc, resource);

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		//获取之前的BeanDefinition数量
		int countBefore = getRegistry().getBeanDefinitionCount();
		//这里不是真正处理的地方,进入
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

进入registerBeanDefinitions(doc, createReaderContext(resource))

@Override
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		//又是do,开始真正的处理
		doRegisterBeanDefinitions(doc.getDocumentElement());
	}

进入

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);
				// We cannot use Profiles.of(...) since profile expressions are not supported
				// in XML config. See SPR-12458 for details.
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					if (logger.isDebugEnabled()) {
						logger.debug("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(root, this.delegate);

//在文档的根级别解析"import", "alias", "bean".元素
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);
		}
	}

我们的bean是有默认的命名空间的,所以进入

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		//判断节点的元素名
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			//我们有bean节点,进入这个方法
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

进入processBeanDefinition(ele, delegate);

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		//把bean元素解析为BeanDefinition
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 把BeanDefinition放入到BeanDefinitionMap
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

当把我们配置文件中的bean标签解析为BeanDefinition,并添加到BeanDefinitionMap中,obtainFreshBeanFactory()方法完成

  • 篇幅太长,每天更新一个方法,哈哈
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗罗的1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值