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配置:

  1. <properties>
  2. <springframework.version>5.0.9.RELEASE</springframework.version>
  3. </properties>
  4. <dependencies>
  5. <dependency>
  6. <groupId>org.springframework</groupId>
  7. <artifactId>spring-context</artifactId>
  8. <version>${springframework.version}</version>
  9. </dependency>
  10. </dependencies>

如果是gradle环境,可以直接在Spring框架project里新增一个module,具体可以参考教程:加上对应的配置
在这里插入图片描述
SpringBean.java:

  1. package com.example.bean;
  2. import org.springframework.beans.factory.InitializingBean;
  3. /**
  4. *
  5. <pre>
  6. * SpringBean
  7. * </pre>
  8. *
  9. *
  10. <pre>
  11. * @author mazq
  12. * 修改记录
  13. * 修改后版本: 修改人: 修改日期: 2020/11/05 10:50 修改内容:
  14. * </pre>
  15. */
  16. public class SpringBean implements InitializingBean {
  17. public SpringBean(){
  18. System.out.println("SpringBean构造函数");
  19. }
  20. @Override
  21. public void afterPropertiesSet() throws Exception {
  22. System.out.println("SpringBean afterPropertiesSet");
  23. }
  24. }

applicationContext.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="springBean" class="com.example.bean.SpringBean" ></bean>
  6. </beans>

测试类,使用ClassPathXmlApplicationContext

  1. package com.example;
  2. import com.example.bean.SpringBean;
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;
  4. /**
  5. *
  6. <pre>
  7. * TestController
  8. * </pre>
  9. *
  10. *
  11. <pre>
  12. * @author mazq
  13. * 修改记录
  14. * 修改后版本: 修改人: 修改日期: 2020/11/05 10:22 修改内容:
  15. * </pre>
  16. */
  17. public class TestApplication {
  18. public static void testClassPathXmlApplicationContext() {
  19. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
  20. SpringBean springBean = context.getBean(SpringBean.class);
  21. System.out.println(springBean);
  22. }
  23. public static void main(String[] args) {
  24. // 测试ClassPathXmlApplicationContext
  25. testClassPathXmlApplicationContext();
  26. }
  27. }

在SpringBean 打断点,debug进行调试:找到#refresh方法
在这里插入图片描述
obtainFreshBeanFactory示例:

  1. /**
  2. * Tell the subclass to refresh the internal bean factory.
  3. * @return the fresh BeanFactory instance
  4. * @see #refreshBeanFactory()
  5. * @see #getBeanFactory()
  6. */
  7. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  8. // 创建BeanFactory
  9. refreshBeanFactory();
  10. // 返回refreshBeanFactory方法创建好的BeanFactory
  11. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  12. if (logger.isDebugEnabled()) {
  13. logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
  14. }
  15. return beanFactory;
  16. }

然后refreshBeanFactory是由哪个基类实现的?我们找来一张uml类图:
在这里插入图片描述
从图可以知道ClassPathXmlApplicationContext通过AbstractRefreshableApplicationContext实现AbstractApplicationContext,所以refreshBeanFactoryAbstractRefreshableApplicationContext#refreshBeanFactory
ok,所以主体的路线,就可以熟悉,用uml时序图表示:
在这里插入图片描述

refreshBeanFactory创建过程

refreshBeanFactory方法是BeanFactory的创建过程,接着跟
org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory代码如下(示例):

  1. /**
  2. * This implementation performs an actual refresh of this context's underlying
  3. * bean factory, shutting down the previous bean factory (if any) and
  4. * initializing a fresh bean factory for the next phase of the context's lifecycle.
  5. */
  6. @Override
  7. protected final void refreshBeanFactory() throws BeansException {
  8. // 先判断是否有BeanFactory
  9. if (hasBeanFactory()) {
  10. // destroy Beans
  11. destroyBeans();
  12. // 关闭BeanFactory
  13. closeBeanFactory();
  14. }
  15. try {
  16. // 实例化DefaultListableBeanFactory
  17. DefaultListableBeanFactory beanFactory = createBeanFactory();
  18. // 设置序列化id
  19. beanFactory.setSerializationId(getId());
  20. // 定义BeanFactory的一些属性(是否允许Bean覆盖,是否允许循环依赖)
  21. customizeBeanFactory(beanFactory);
  22. // 加载应用中的BeanDefinition
  23. loadBeanDefinitions(beanFactory);
  24. this.beanFactory = beanFactory;
  25. }
  26. catch (IOException ex) {
  27. throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
  28. }
  29. }

{@link org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions}

  1. /**
  2. * Loads the bean definitions via an XmlBeanDefinitionReader.
  3. * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
  4. * @see #initBeanDefinitionReader
  5. * @see #loadBeanDefinitions
  6. */
  7. @Override
  8. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
  9. // Create a new XmlBeanDefinitionReader for the given BeanFactory.
  10. // 给BeanFactory实例化一个XmlBeanDefinitionReader实例
  11. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
  12. // Configure the bean definition reader with this context's
  13. // resource loading environment.
  14. beanDefinitionReader.setEnvironment(this.getEnvironment());
  15. beanDefinitionReader.setResourceLoader(this);
  16. beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
  17. // Allow a subclass to provide custom initialization of the reader,
  18. // then proceed with actually loading the bean definitions.
  19. // 给子类提供初始化XmlBeanDefinitionReader的模板方法
  20. initBeanDefinitionReader(beanDefinitionReader);
  21. // 重点在这,继续跟
  22. loadBeanDefinitions(beanDefinitionReader);
  23. }
  24. // org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)
  25. protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
  26. Resource[] configResources = getConfigResources();
  27. if (configResources != null) {
  28. // 继续跟
  29. reader.loadBeanDefinitions(configResources);
  30. }
  31. String[] configLocations = getConfigLocations();
  32. if (configLocations != null) {
  33. reader.loadBeanDefinitions(configLocations);
  34. }
  35. }

{@link org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions}

  1. @Override
  2. public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
  3. Assert.notNull(resources, "Resource array must not be null");
  4. int counter = 0;
  5. // 变量资源对象,加载BeanDefinition
  6. for (Resource resource : resources) {
  7. // 在这里,经过debug,调到XmlBeanDefinitionReader.loadBeanDefinitions(resource)
  8. counter += loadBeanDefinitions(resource);
  9. }
  10. // 返回统计数量,表示总共有多少个BeanDefinition
  11. return counter;
  12. }

XmlBeanDefinitionReader
{@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions}

  1. @Override
  2. public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
  3. return loadBeanDefinitions(new EncodedResource(resource));
  4. }
  5. // 省略...
  6. /**
  7. * Load bean definitions from the specified XML file.
  8. * @param encodedResource the resource descriptor for the XML file,
  9. * allowing to specify an encoding to use for parsing the file
  10. * @return the number of bean definitions found
  11. * @throws BeanDefinitionStoreException in case of loading or parsing errors
  12. */
  13. public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
  14. Assert.notNull(encodedResource, "EncodedResource must not be null");
  15. if (logger.isInfoEnabled()) {
  16. logger.info("Loading XML bean definitions from " + encodedResource);
  17. }
  18. // 用ThreadLocal存放资源对象,目的是保证线程安全
  19. Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
  20. if (currentResources == null) {
  21. currentResources = new HashSet<>(4);
  22. this.resourcesCurrentlyBeingLoaded.set(currentResources);
  23. }
  24. if (!currentResources.add(encodedResource)) {
  25. throw new BeanDefinitionStoreException(
  26. "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
  27. }
  28. try {
  29. InputStream inputStream = encodedResource.getResource().getInputStream();
  30. try {
  31. InputSource inputSource = new InputSource(inputStream);
  32. if (encodedResource.getEncoding() != null) {
  33. inputSource.setEncoding(encodedResource.getEncoding());
  34. }
  35. // 核心,往下跟
  36. return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
  37. }
  38. finally {
  39. inputStream.close();
  40. }
  41. }
  42. catch (IOException ex) {
  43. throw new BeanDefinitionStoreException(
  44. "IOException parsing XML document from " + encodedResource.getResource(), ex);
  45. }
  46. finally {
  47. currentResources.remove(encodedResource);
  48. if (currentResources.isEmpty()) {
  49. this.resourcesCurrentlyBeingLoaded.remove();
  50. }
  51. }
  52. }
  53. /**
  54. * Actually load bean definitions from the specified XML file.
  55. * @param inputSource the SAX InputSource to read from
  56. * @param resource the resource descriptor for the XML file
  57. * @return the number of bean definitions found
  58. * @throws BeanDefinitionStoreException in case of loading or parsing errors
  59. * @see #doLoadDocument
  60. * @see #registerBeanDefinitions
  61. */
  62. protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
  63. throws BeanDefinitionStoreException {
  64. try {
  65. // 读取xml信息,将xml信息保存在Document对象
  66. Document doc = doLoadDocument(inputSource, resource);
  67. // 封装BeanDefinitions并注册,继续解析Document对象,往下跟
  68. return registerBeanDefinitions(doc, resource);
  69. }
  70. catch (BeanDefinitionStoreException ex) {
  71. throw ex;
  72. }
  73. catch (SAXParseException ex) {
  74. throw new XmlBeanDefinitionStoreException(resource.getDescription(),
  75. "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
  76. }
  77. catch (SAXException ex) {
  78. throw new XmlBeanDefinitionStoreException(resource.getDescription(),
  79. "XML document from " + resource + " is invalid", ex);
  80. }
  81. catch (ParserConfigurationException ex) {
  82. throw new BeanDefinitionStoreException(resource.getDescription(),
  83. "Parser configuration exception parsing XML from " + resource, ex);
  84. }
  85. catch (IOException ex) {
  86. throw new BeanDefinitionStoreException(resource.getDescription(),
  87. "IOException parsing XML document from " + resource, ex);
  88. }
  89. catch (Throwable ex) {
  90. throw new BeanDefinitionStoreException(resource.getDescription(),
  91. "Unexpected exception parsing XML document from " + resource, ex);
  92. }
  93. }
  94. /**
  95. * Register the bean definitions contained in the given DOM document.
  96. * Called by {@code loadBeanDefinitions}.
  97. * <p>Creates a new instance of the parser class and invokes
  98. * {@code registerBeanDefinitions} on it.
  99. * @param doc the DOM document
  100. * @param resource the resource descriptor (for context information)
  101. * @return the number of bean definitions found
  102. * @throws BeanDefinitionStoreException in case of parsing errors
  103. * @see #loadBeanDefinitions
  104. * @see #setDocumentReaderClass
  105. * @see BeanDefinitionDocumentReader#registerBeanDefinitions
  106. */
  107. public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
  108. BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
  109. // 获取已有的BeanDefinition数量
  110. int countBefore = getRegistry().getBeanDefinitionCount();
  111. // 注册BeanDefinition,关注点:registerBeanDefinitions、createReaderContext
  112. documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
  113. // 返回新注册的BeanDefinition统计数量
  114. return getRegistry().getBeanDefinitionCount() - countBefore;
  115. }

{@link org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#registerBeanDefinitions}

  1. /**
  2. * This implementation parses bean definitions according to the "spring-beans" XSD
  3. * (or DTD, historically).
  4. * <p>Opens a DOM Document; then initializes the default settings
  5. * specified at the {@code <beans/>} level; then parses the contained bean definitions.
  6. */
  7. @Override
  8. public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
  9. this.readerContext = readerContext;
  10. logger.debug("Loading bean definitions");
  11. Element root = doc.getDocumentElement();
  12. // 往下跟,从xml根节点开始解析文件
  13. doRegisterBeanDefinitions(root);
  14. }
  15. /**
  16. * Register each bean definition within the given root {@code <beans/>} element.
  17. */
  18. protected void doRegisterBeanDefinitions(Element root) {
  19. // Any nested <beans> elements will cause recursion in this method. In
  20. // order to propagate and preserve <beans> default-* attributes correctly,
  21. // keep track of the current (parent) delegate, which may be null. Create
  22. // the new (child) delegate with a reference to the parent for fallback purposes,
  23. // then ultimately reset this.delegate back to its original (parent) reference.
  24. // this behavior emulates a stack of delegates without actually necessitating one.
  25. BeanDefinitionParserDelegate parent = this.delegate;
  26. this.delegate = createDelegate(getReaderContext(), root, parent);
  27. if (this.delegate.isDefaultNamespace(root)) {
  28. // profile(环境校验)
  29. String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
  30. if (StringUtils.hasText(profileSpec)) {
  31. String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
  32. profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
  33. // 不是当前profile的,跳过
  34. if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
  35. if (logger.isInfoEnabled()) {
  36. logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
  37. "] not matching: " + getReaderContext().getResource());
  38. }
  39. return;
  40. }
  41. }
  42. }
  43. // preProcessXml模板方法
  44. preProcessXml(root);
  45. // 重点是parseBeanDefinitions
  46. parseBeanDefinitions(root, this.delegate);
  47. // postProcessXml 同样是模板方法 过
  48. postProcessXml(root);
  49. this.delegate = parent;
  50. }
  51. /**
  52. * Parse the elements at the root level in the document:
  53. * "import", "alias", "bean".
  54. * @param root the DOM root element of the document
  55. */
  56. protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
  57. if (delegate.isDefaultNamespace(root)) {
  58. NodeList nl = root.getChildNodes();
  59. for (int i = 0; i < nl.getLength(); i++) {
  60. Node node = nl.item(i);
  61. if (node instanceof Element) {
  62. Element ele = (Element) node;
  63. if (delegate.isDefaultNamespace(ele)) {
  64. // 解析default namespace下面的元素
  65. parseDefaultElement(ele, delegate);
  66. }
  67. else {
  68. // 解析自定义标签元素
  69. delegate.parseCustomElement(ele);
  70. }
  71. }
  72. }
  73. }
  74. else {
  75. delegate.parseCustomElement(root);
  76. }
  77. }
  78. private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
  79. // import元素处理
  80. if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
  81. importBeanDefinitionResource(ele);
  82. }
  83. // alias元素处理
  84. else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
  85. processAliasRegistration(ele);
  86. }
  87. // bean元素处理
  88. else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
  89. processBeanDefinition(ele, delegate);
  90. }
  91. // 嵌套beans处理
  92. else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
  93. // recurse
  94. doRegisterBeanDefinitions(ele);
  95. }
  96. }

bean元素处理,本文挑beana元素的处理进行讲述:

  1. /**
  2. * Process the given bean element, parsing the bean definition
  3. * and registering it with the registry.
  4. */
  5. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
  6. //解析Bean元素为BeanDefinition,再通过BeanDefinitionHolder封装成BeanDefinitionHolder对象
  7. BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
  8. if (bdHolder != null) {
  9. // 有自定义属性会进行相应的解析
  10. bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
  11. try {
  12. // Register the final decorated instance.
  13. // BeanDefinition的注册过程
  14. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
  15. }
  16. catch (BeanDefinitionStoreException ex) {
  17. getReaderContext().error("Failed to register bean definition with name '" +
  18. bdHolder.getBeanName() + "'", ele, ex);
  19. }
  20. // Send registration event.
  21. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
  22. }
  23. }
  1. public static void registerBeanDefinition(
  2. BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
  3. throws BeanDefinitionStoreException {
  4. // Register bean definition under primary name.
  5. // 根据beanName注册BeanDefinition
  6. String beanName = definitionHolder.getBeanName();
  7. registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
  8. // Register aliases for bean name, if any.
  9. // 如果有别名,根据别名再注册一遍
  10. String[] aliases = definitionHolder.getAliases();
  11. if (aliases != null) {
  12. for (String alias : aliases) {
  13. registry.registerAlias(beanName, alias);
  14. }
  15. }
  16. }