Ioc源码剖析——BeanFactory创建流程

  • Post author:
  • Post category:其他




关键步骤

BeanFactory注册涉及到几个关键的的步骤

1、Resource定位:就是找到定义JavaBean信息的xml文件,并将其封装为Resource对象

2、BeanDedefinition载入:把用户定义好的Javabean表示为Ioc容器内部的数据结构

3、注册BeanDefinition到ioc容器



过程分析

分析BeanFactory的创建流程不是简单的去看如何new一个BeanFactory对象,而是看BeanDefinition如何加载到BeanFactory这一过程。

我们通过上一篇文章《Ioc源码分析-ioc容器初始化主流程》可以知道BeanDefinition的注册到BeanFactory是在obtainFreshBeanFactory这个方法中,接下来我们就点进这个方法看一下,他是如何注册的

在这里插入图片描述

我们点进这个方法以后就可以看到一个名叫refreshBeanFactory的方法,然后我们看一下这个方法

	protected final void refreshBeanFactory() throws BeansException {
		// 判断是否已经存在beanFactory
		if (hasBeanFactory()) {
			// 销毁beans
			destroyBeans();
			// 关闭工厂
			closeBeanFactory();
		}
		try {
			// 实例化DefaultListableBeanFactory
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			// 设置序列化id
			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);
		}
	}

那么通过上面的方法我们,我们可以看到有一个LodaBeanDefinition方法,加载BeanDefinition,这个应该就是我们要看的方法入口,接着点进去

熟悉源码的同学都知道,在spring源码中,通常实际的执行实现方法通常方法名都会有doXXXX,createXXX等动词开头,所以我们经过依次调用多个类的 loadBeanDefinitions 方法 —> AbstractXmlApplicationContext —>

AbstractBeanDefinitionReader —> XmlBeanDefinitionReader ⼀直执行到

XmlBeanDefinitionReader 的 doLoadBeanDefinitions 方法

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

		try {
			// 解析xml文件,获取document对象
			Document doc = doLoadDocument(inputSource, resource);
			// 注册BeanDefinition
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
		}

同样经过一些重载方法,我们定位到registerBeanDefinition方法

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		// 获取已有BeanDefinition的个数
		int countBefore = getRegistry().getBeanDefinitionCount();
		// 注册BeanDefinition
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

这个方法中我们重点关注两个方法,一个是createReaderContexet方法,一个是registerBeanDefinition方法

先看createReaderContext

在这里插入图片描述

我们可以看到这个方法初始化了nameSpaceHandler

然后我们再返回去看registerBeanDefinition方法

	@Override
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		doRegisterBeanDefinitions(doc.getDocumentElement());
	}

找到doRegisterBeanDefinition方法

	protected void doRegisterBeanDefinitions(Element root) {
		............
		preProcessXml(root);
		parseBeanDefinitions(root, this.delegate);
		postProcessXml(root);

		this.delegate = parent;
	}

这个方法里面我们重点关注parseBeanDefinition方法,perProcessXml前置处理,和PostProcessxml后置处理先不看

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

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		// import元素
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		// alias元素
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		// bean元素
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		// nested元素
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

我们看processBeanDefinition方法解析bean标签

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	           .............
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			................
	}

我们最后看registerBeanDefinition方法

	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
    ...................
        // 判断Bean是否已经存在
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
			...........
		}
		else {
			// 判断该bean有没有正在被注册
			if (hasBeanCreationStarted()) {
				...............
			}
			// 注册到BeanFactory中
			else {
				// Still in startup registration phase
				// 存放
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

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

那我们可以看出BeanDefinition注册到BeanFactory中,其实就是把BeanDefinition存放到一个map中

	/** Map of bean definition objects, keyed by bean name. */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);



时序图

在这里插入图片描述



版权声明:本文为afjaklsdflka原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。