Spring5.0源码学习系列之浅谈BeanFactory创建

Spring5.0源码学习系列之浅谈BeanFactory创建过程
系列文章目录 提示:Spring源码学习专栏链接

@TOC

博客前言介绍 提示:在上一章的学习中,我们简单了解了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配置:
5.0.9.RELEASE org.springframework spring-context ${springframework.version}

如果是gradle环境,可以直接在Spring框架project里新增一个module,具体可以参考教程:加上对应的配置

Spring5.0源码学习系列之浅谈BeanFactory创建
文章图片
在这里插入图片描述
SpringBean.java:
package com.example.bean; import org.springframework.beans.factory.InitializingBean; /** *
*SpringBean *

* *
* @author mazq * 修改记录 *修改后版本:修改人:修改日期: 2020/11/05 10:50修改内容: *

*/ public class SpringBean implements InitializingBean {public SpringBean(){ System.out.println("SpringBean构造函数"); }@Override public void afterPropertiesSet() throws Exception { System.out.println("SpringBean afterPropertiesSet"); } }

applicationContext.xml:

测试类,使用ClassPathXmlApplicationContext
package com.example; import com.example.bean.SpringBean; import org.springframework.context.support.ClassPathXmlApplicationContext; /** *
*TestController *

* *
* @author mazq * 修改记录 *修改后版本:修改人:修改日期: 2020/11/05 10:22修改内容: *

*/ public class TestApplication { public static void testClassPathXmlApplicationContext() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); SpringBeanspringBean = context.getBean(SpringBean.class); System.out.println(springBean); }public static void main(String[] args) { // 测试ClassPathXmlApplicationContext testClassPathXmlApplicationContext(); } }

在SpringBean 打断点,debug进行调试:找到#refresh方法

Spring5.0源码学习系列之浅谈BeanFactory创建
文章图片
在这里插入图片描述
obtainFreshBeanFactory示例:
/** * Tell the subclass to refresh the internal bean factory. * @return the fresh BeanFactory instance * @see #refreshBeanFactory() * @see #getBeanFactory() */ protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { // 创建BeanFactory refreshBeanFactory(); // 返回refreshBeanFactory方法创建好的BeanFactory ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }

然后refreshBeanFactory是由哪个基类实现的?我们找来一张uml类图:

Spring5.0源码学习系列之浅谈BeanFactory创建
文章图片
在这里插入图片描述
从图可以知道 ClassPathXmlApplicationContext通过 AbstractRefreshableApplicationContext实现 AbstractApplicationContext,所以 refreshBeanFactoryAbstractRefreshableApplicationContext#refreshBeanFactory
ok,所以主体的路线,就可以熟悉,用uml时序图表示:

Spring5.0源码学习系列之浅谈BeanFactory创建
文章图片
在这里插入图片描述 二、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. */ @Override protected final void refreshBeanFactory() throws BeansException { // 先判断是否有BeanFactory if (hasBeanFactory()) { // destroy Beans destroyBeans(); // 关闭BeanFactory closeBeanFactory(); } try { // 实例化DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = createBeanFactory(); // 设置序列化id beanFactory.setSerializationId(getId()); // 定义BeanFactory的一些属性(是否允许Bean覆盖,是否允许循环依赖) customizeBeanFactory(beanFactory); // 加载应用中的BeanDefinition loadBeanDefinitions(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 */ @Override protected 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}
@Override public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; // 变量资源对象,加载BeanDefinition for (Resource resource : resources) { // 在这里,经过debug,调到XmlBeanDefinitionReader.loadBeanDefinitions(resource) counter += loadBeanDefinitions(resource); } // 返回统计数量,表示总共有多少个BeanDefinition return counter; }

XmlBeanDefinitionReader
{@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions}
@Override public 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 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}. * 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、createReaderContext documentReader.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). * Opens a DOM Document; then initializes the default settings * specified at the {@code } level; then parses the contained bean definitions. */ @Override public 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 } element. */ protected void doRegisterBeanDefinitions(Element root) { // Any nested elements will cause recursion in this method. In // order to propagate and preserve 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); // 重点是parseBeanDefinitions parseBeanDefinitions(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)) { // recurse doRegisterBeanDefinitions(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)); } }


知识点归纳 【Spring5.0源码学习系列之浅谈BeanFactory创建】提示:这里对文章进行归纳:
Spring5.0源码学习系列之浅谈BeanFactory创建
文章图片
在这里插入图片描述

    推荐阅读