show: stepversion: 1.0
enable_checker: true
浅谈SpringFramework的BeanFactory创建过程
博客前言介绍
提示:在前面章节的学习中,我们简单了解了Spring IoC容器启动初始化的主流程,不过并没有详细解释,因为代码比较复杂,没有做长篇大论,所以本文接着学习BenFactory的创建过程,学习源码建议带着疑问去学,一点点跟,时间积累之后就可以串起来
提示:以下是本篇文章正文内容,下面案例可供参考
获取BeanFactory主流程
在前面的学习中,#refresh是IoC容器创建很关键的主线,在代码里,可以找到obtainFreshBeanFactory这个比较关键的方法,这个方法就是BeanFactory的创建过程方法,本文ClassPathXmlApplicationContext为准,进行源码的学习,上篇博客是以AnnotationApplicationContext为准进行简单的分析,本文继续比较详细的讲述
实验环境:
- SpringFramework版本
- Springframework5.0.x
- 开发环境
- JAR管理:gradle 4.9/ Maven3.+
- 开发IDE:IntelliJ IDEA 2018.2.5
- JDK:jdk1.8.0_31
- Git Server:Git fro window 2.8.3
- Git Client:SmartGit18.1.5(可选)
maven项目,需要加上pom配置:
<properties><springframework.version>5.0.9.RELEASE</springframework.version></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${springframework.version}</version></dependency></dependencies>
如果是gradle环境,可以直接在Spring框架project里新增一个module,具体可以参考教程:加上对应的配置

SpringBean.java:
package com.example.bean;import org.springframework.beans.factory.InitializingBean;/***<pre>* SpringBean* </pre>**<pre>* @author mazq* 修改记录* 修改后版本: 修改人: 修改日期: 2020/11/05 10:50 修改内容:* </pre>*/public class SpringBean implements InitializingBean {public SpringBean(){System.out.println("SpringBean构造函数");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("SpringBean afterPropertiesSet");}}
applicationContext.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"><bean id="springBean" class="com.example.bean.SpringBean" ></bean></beans>
测试类,使用ClassPathXmlApplicationContext
package com.example;import com.example.bean.SpringBean;import org.springframework.context.support.ClassPathXmlApplicationContext;/***<pre>* TestController* </pre>**<pre>* @author mazq* 修改记录* 修改后版本: 修改人: 修改日期: 2020/11/05 10:22 修改内容:* </pre>*/public class TestApplication {public static void testClassPathXmlApplicationContext() {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");SpringBean springBean = context.getBean(SpringBean.class);System.out.println(springBean);}public static void main(String[] args) {// 测试ClassPathXmlApplicationContexttestClassPathXmlApplicationContext();}}
在SpringBean 打断点,debug进行调试:找到#refresh方法

obtainFreshBeanFactory示例:
/*** Tell the subclass to refresh the internal bean factory.* @return the fresh BeanFactory instance* @see #refreshBeanFactory()* @see #getBeanFactory()*/protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {// 创建BeanFactoryrefreshBeanFactory();// 返回refreshBeanFactory方法创建好的BeanFactoryConfigurableListableBeanFactory beanFactory = getBeanFactory();if (logger.isDebugEnabled()) {logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);}return beanFactory;}
然后refreshBeanFactory是由哪个基类实现的?我们找来一张uml类图:

从图可以知道ClassPathXmlApplicationContext通过AbstractRefreshableApplicationContext实现AbstractApplicationContext,所以refreshBeanFactory是AbstractRefreshableApplicationContext#refreshBeanFactory
ok,所以主体的路线,就可以熟悉,用uml时序图表示:

refreshBeanFactory创建过程
refreshBeanFactory方法是BeanFactory的创建过程,接着跟org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory代码如下(示例):
/*** This implementation performs an actual refresh of this context's underlying* bean factory, shutting down the previous bean factory (if any) and* initializing a fresh bean factory for the next phase of the context's lifecycle.*/@Overrideprotected final void refreshBeanFactory() throws BeansException {// 先判断是否有BeanFactoryif (hasBeanFactory()) {// destroy BeansdestroyBeans();// 关闭BeanFactorycloseBeanFactory();}try {// 实例化DefaultListableBeanFactoryDefaultListableBeanFactory beanFactory = createBeanFactory();// 设置序列化idbeanFactory.setSerializationId(getId());// 定义BeanFactory的一些属性(是否允许Bean覆盖,是否允许循环依赖)customizeBeanFactory(beanFactory);// 加载应用中的BeanDefinitionloadBeanDefinitions(beanFactory);this.beanFactory = beanFactory;}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}}
{@link org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions}
/*** Loads the bean definitions via an XmlBeanDefinitionReader.* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader* @see #initBeanDefinitionReader* @see #loadBeanDefinitions*/@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// Create a new XmlBeanDefinitionReader for the given BeanFactory.// 给BeanFactory实例化一个XmlBeanDefinitionReader实例XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// Configure the bean definition reader with this context's// resource loading environment.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.// 给子类提供初始化XmlBeanDefinitionReader的模板方法initBeanDefinitionReader(beanDefinitionReader);// 重点在这,继续跟loadBeanDefinitions(beanDefinitionReader);}// org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)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);}}
{@link org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions}
@Overridepublic int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {Assert.notNull(resources, "Resource array must not be null");int counter = 0;// 变量资源对象,加载BeanDefinitionfor (Resource resource : resources) {// 在这里,经过debug,调到XmlBeanDefinitionReader.loadBeanDefinitions(resource)counter += loadBeanDefinitions(resource);}// 返回统计数量,表示总共有多少个BeanDefinitionreturn counter;}
XmlBeanDefinitionReader类{@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions}
@Overridepublic int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {return loadBeanDefinitions(new EncodedResource(resource));}// 省略.../*** Load bean definitions from the specified XML file.* @param encodedResource the resource descriptor for the XML file,* allowing to specify an encoding to use for parsing the file* @return the number of bean definitions found* @throws BeanDefinitionStoreException in case of loading or parsing errors*/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);}// 用ThreadLocal存放资源对象,目的是保证线程安全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();}}}/*** Actually load bean definitions from the specified XML file.* @param inputSource the SAX InputSource to read from* @param resource the resource descriptor for the XML file* @return the number of bean definitions found* @throws BeanDefinitionStoreException in case of loading or parsing errors* @see #doLoadDocument* @see #registerBeanDefinitions*/protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {// 读取xml信息,将xml信息保存在Document对象Document doc = doLoadDocument(inputSource, resource);// 封装BeanDefinitions并注册,继续解析Document对象,往下跟return registerBeanDefinitions(doc, resource);}catch (BeanDefinitionStoreException ex) {throw ex;}catch (SAXParseException ex) {throw new XmlBeanDefinitionStoreException(resource.getDescription(),"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);}catch (SAXException ex) {throw new XmlBeanDefinitionStoreException(resource.getDescription(),"XML document from " + resource + " is invalid", ex);}catch (ParserConfigurationException ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"Parser configuration exception parsing XML from " + resource, ex);}catch (IOException ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"IOException parsing XML document from " + resource, ex);}catch (Throwable ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"Unexpected exception parsing XML document from " + resource, ex);}}/*** Register the bean definitions contained in the given DOM document.* Called by {@code loadBeanDefinitions}.* <p>Creates a new instance of the parser class and invokes* {@code registerBeanDefinitions} on it.* @param doc the DOM document* @param resource the resource descriptor (for context information)* @return the number of bean definitions found* @throws BeanDefinitionStoreException in case of parsing errors* @see #loadBeanDefinitions* @see #setDocumentReaderClass* @see BeanDefinitionDocumentReader#registerBeanDefinitions*/public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();// 获取已有的BeanDefinition数量int countBefore = getRegistry().getBeanDefinitionCount();// 注册BeanDefinition,关注点:registerBeanDefinitions、createReaderContextdocumentReader.registerBeanDefinitions(doc, createReaderContext(resource));// 返回新注册的BeanDefinition统计数量return getRegistry().getBeanDefinitionCount() - countBefore;}
{@link org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#registerBeanDefinitions}
/*** This implementation parses bean definitions according to the "spring-beans" XSD* (or DTD, historically).* <p>Opens a DOM Document; then initializes the default settings* specified at the {@code <beans/>} level; then parses the contained bean definitions.*/@Overridepublic void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext;logger.debug("Loading bean definitions");Element root = doc.getDocumentElement();// 往下跟,从xml根节点开始解析文件doRegisterBeanDefinitions(root);}/*** Register each bean definition within the given root {@code <beans/>} element.*/protected void doRegisterBeanDefinitions(Element root) {// Any nested <beans> elements will cause recursion in this method. In// order to propagate and preserve <beans> default-* attributes correctly,// keep track of the current (parent) delegate, which may be null. Create// the new (child) delegate with a reference to the parent for fallback purposes,// then ultimately reset this.delegate back to its original (parent) reference.// this behavior emulates a stack of delegates without actually necessitating one.BeanDefinitionParserDelegate parent = this.delegate;this.delegate = createDelegate(getReaderContext(), root, parent);if (this.delegate.isDefaultNamespace(root)) {// profile(环境校验)String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);if (StringUtils.hasText(profileSpec)) {String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);// 不是当前profile的,跳过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模板方法preProcessXml(root);// 重点是parseBeanDefinitionsparseBeanDefinitions(root, this.delegate);// postProcessXml 同样是模板方法 过postProcessXml(root);this.delegate = parent;}/*** Parse the elements at the root level in the document:* "import", "alias", "bean".* @param root the DOM root element of the document*/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)) {// 解析default namespace下面的元素parseDefaultElement(ele, delegate);}else {// 解析自定义标签元素delegate.parseCustomElement(ele);}}}}else {delegate.parseCustomElement(root);}}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);}// 嵌套beans处理else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// recursedoRegisterBeanDefinitions(ele);}}
bean元素处理,本文挑beana元素的处理进行讲述:
/*** Process the given bean element, parsing the bean definition* and registering it with the registry.*/protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {//解析Bean元素为BeanDefinition,再通过BeanDefinitionHolder封装成BeanDefinitionHolder对象BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);if (bdHolder != null) {// 有自定义属性会进行相应的解析bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);try {// Register the final decorated instance.// BeanDefinition的注册过程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));}}
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {// Register bean definition under primary name.// 根据beanName注册BeanDefinitionString beanName = definitionHolder.getBeanName();registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());// Register aliases for bean name, if any.// 如果有别名,根据别名再注册一遍String[] aliases = definitionHolder.getAliases();if (aliases != null) {for (String alias : aliases) {registry.registerAlias(beanName, alias);}}}
