Spring启动流程(二)之Spring加载Bean Definition的流程

版权声明:如果觉得文章对你有用,转载不需要联系作者,但请注明出处 https://blog.csdn.net/jinxin70/article/details/83505352

继上篇Spring启动流程(一)

prepareRefresh()

prepareRefresh();//初始化配置和环境

obtainFreshBeanFactory()

// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    return getBeanFactory();
}

下面的refreshBeanFactory方法的主要工作:加载applicationContext.xml配置文件,创建Spring Bean Definition

       @Override
	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(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);
		}
	}

DefaultListableBeanFactory是一个很重要的Bean工厂类,内部存储了bean definition信息,即bean的元数据,即描述bean的信息,这些内容存放在DefaultListableBeanFactory内的不同的容器中(map、list、set);

DefaultListableBeanFactory可以通过后置处理器扩展;

loadBeanDefinitions方法传入DefaultListableBeanFactory,内部是将bean definitions信息设置到bean factory,如何设置呢?会使用不同的bean definition readers来读取配置文件中配置的bean,然后设置到DefaultListableBeanFactory内部的不同数据结构中。

比如常用的XmlBeanDefinitionReader。可以看一下BeanDefinitionReader接口的类继承层次图如下。

Bean Definition大致创建过程:

1、加载applicationContext.xml配置文件

2、解析xml

3、将xml中的内容转化为Spring Bean Definition。

下面是一些细节及关键类:

1、加载资源配置文件

AbstractBeanDefinitionReader.java

Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);//通过类加载器在classpath下找到applicationContext配置文件的绝对路径

2、解析生成的xml对象转为Spring BeanDefinition:

DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions

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

依次遍历所有遇到的元素(空行、换行、注释、xml节点),但是只会解析xml节点(node instanceof Element) 。

内部除了namespace是http://www.springframework.org/schema/beans的,其他节点解析都走delegate.parseCustomElement(ele);

        @Nullable
	public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {
			return null;
		}
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

这里的namespaceHandler是从META-INF/spring-handlers文件读取的,之后通过反射初始化使用

不过这里不管是通过哪个namespaceHandler,都要通过NamespaceHandlerSupport转发处理,因为所有的namespaceHandler都是继承NamespaceHandlerSupport,重写了init方法,init方法只是建立xml节点属性->BeanDefinitionParser的映射关系。

protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
    this.parsers.put(elementName, parser);
}

接着会从这个映射关系里找命名空间处理器然后处理

        @Override
	@Nullable
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		BeanDefinitionParser parser = findParserForElement(element, parserContext);
		return (parser != null ? parser.parse(element, parserContext) : null);
	}

如果是开启注解的包扫描配置:

<context:component-scan base-package="com.baby.kim">

会调用ComponentScanBeanDefinitionParser,将使用@Service,@Controller等注解的对象转为beanDefinition。

其他的Context namespace下的处理器还有

3、注册beanDefinition到DefaultListableBeanFactory

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

3.1、最终调用

将beanDefinition信息保存到DefaultListableBeanFactory的属性中。

this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);

总结:

这一篇主要介绍了Spring是如何解析和将在bean definition到bean factory中的,

下一篇Spring启动流程(三)之Bean的实例化将介绍Bean的实例化过程

猜你喜欢

转载自blog.csdn.net/jinxin70/article/details/83505352