【Spring 源码】Spring 加载资源并装配对象的过程(XmlBeanDefinitionReader)

Spring 加载资源并装配对象过程

在Spring中对XML配置文件的解析从3.1版本开始不再推荐使用XmlBeanFactory而是使用XmlBeanDefinitionReader。

ClassPathResource resource = new ClassPathResource("bean.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);
// 上面步骤只是将spring bean的配置文件解析并注册到spring容器中,并未实例化
// 经过下面的步骤,才会执行实例化
Person person = (Person) factory.getBean("person");
person.say();

解析XML主要流程:
1、定义好Spring 的配置文件
2、通过Resource对象将Spring配置文件进行抽象,抽象成一个Resource对象
3、定义好Bean工厂(各种BeanFactory)
4、定义好XmlBeanDefinitionReader对象,并将工厂作为参数传递进去供后续回调使用
5、通过XmlBeanDefinitionReader对象读取之前抽象出的Resource对象(包含了XML文件的解析过程)
6、本质上,XML文件的解析是由XmlBeanDefinitionReader对象交由BeanDefinitionParserDelegate委托来完成的,实质上这里使用了委托设计模式。--注册bean定义到容器
7、IoC容器创建完闭,用户可以通过容器获取所需对象信息。--实例化

重要:在DefaultBeanDefinitionDocumentReader类中的doRegisterBeanDefinitions方法使用了经典的模板方法设计模式,子类可以重写preProcessXml与poseProcessXml方法,实现对XML配置文件的自定义扩展。

singleton bean的实例化过程:(org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String))
1、Spring 的bean实际上是缓存在 ConcurrentHashMap(singletonObjects)中(org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean))
2、在创建bean之前,首先需要将该bean的创建标识设定好,表示该bean已经或即将被创建,为的是增强缓存效率(org.springframework.beans.factory.support.AbstractBeanFactory#markBeanAsCreated)
3、根据bean的scope属性确定是singleton还是prototype等范围,然后创建相应的bean对象。
4、通过Java反射来创建bean实例,在创建之前首先检查访问修饰符,如果不是public的,则调用setAccessible(true)来突破Java的语法限制,使得可以通过如私有构造方法来创建对象实例。(org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean)
5、接下来,寻找bean的属性值,完成属性注入(org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean)
6、将所有创建出的singleton实例添加到缓存当中,供下次使用调用(org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton)


涉及的源代码UML

ClassPathResource

DefaultListableBeanFactory

XmlBeanDefinitionReader

验证代码

代码结构

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>spring</groupId>
  <artifactId>zqq</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>zqq</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
    </dependency>
    <!--1)Spring核心依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.3.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.3.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.4.RELEASE</version>
    </dependency>
    <!--Spring DAO层依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>4.3.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>4.3.4.RELEASE</version>
    </dependency>
    <!--3)Spring Web相关依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.3.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.4.RELEASE</version>
    </dependency>
    <!--4)Spring test相关依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.3.4.RELEASE</version>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

App.java

package spring;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;

public class App 
{
    public static void main( String[] args )
    {
        ClassPathResource resource = new ClassPathResource("beans.xml");
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        reader.loadBeanDefinitions(resource);
        Person person = (Person) factory.getBean("person");
        person.say();
    }
}

Person.java

package spring;

public interface Person {
    void say();

}

PersonImpl.java

package spring;

public class PersonImpl implements Person {
    String name="";

    @Override
    public void say() {
        System.out.println(name);
    }

    public void setName(String name) {
        this.name=name;
    }
}

注意:由于开始创建的是quickstart工程,没有resources目录,而beans.xml需要放到该目录下才会被找到,需要在project structure的modules管理中新建资源文件夹。

参考资料:
Spring如何解析XML文件——Spring源码之XML初解析

posted @ 2019-10-28 15:06  风动静泉  阅读(539)  评论(0编辑  收藏  举报