一、Spring容器基本概念

Spring通过IoC容器管理Bean与Bean之间的依赖关系,并由 IoC 容器完成对象的注入。IoC容器在完成这些底层工作的基础上,还提供了Bean实例缓存、生命周期管理、Bean实例代理、事件发布、资源装载等高级服务。

BeanFactory是Spring框架的基础设施,面向Spring本身,负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期。

ApplicationContext面向使用Spring框架的开发者,除了提供上述 BeanFactory 所能提供的功能之外还提供了国际化支持资源访问事件传递

二、什么是IOC

IoC(Inversion of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。被Spring管理的这些对象就是Spring Bean

  • 控制:指的是对象创建(实例化、管理)的权力
  • 反转:控制权交给外部环境(Spring 框架、IoC 容器)

三、Spring IOC工作流程

初始化的入口

在Spring应用中实例化一个ApplicationContext即可创建一个IoC容器。我们可以从这个构造方法开始,探究一下IoC容器的初始化过程。

以ClassPathXmlApplicationContext为例,在main()方法中实例化ClassPathXmlApplicationContext创建一个IoC容器。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?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">

    <!-- 定义 userService Bean -->
    <bean id="AdminEntity" class="com.test.AdminEntity">
        <property name="name" value="John Doe" />
    </bean>

</beans>
1
2
3
4
5
6
7
public class SpringTest {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
        System.out.println("number : " + ctx.getBeanDefinitionCount());
        System.out.println(((AdminEntity) ctx.getBean("AdminEntity")).getName());
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
    this(configLocations, true, (ApplicationContext)null);
}

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
    // 动态地确定用哪个加载器去加载我们的配置文件
    super(parent);

    // 告诉读取器 配置文件放在哪里,该方法继承于爷类 AbstractRefreshableConfigApplicationContext
    this.setConfigLocations(configLocations);

    if (refresh) {
        // 初始化容器
        this.refresh();
    }
}

可以看到该构造方法被重载了,可以传递 configLocation 字符串或者字符串数组,也就是说,可以传递过个配置文件的地址。默认刷新为true,parent 容器为null。

资源定位

Spring IoC容器对Bean定义资源的载入是从其父类 AbstractApplicationContext 实现的 refresh() 方法函数开始的,该方法就是 IoC 容器初始化的入口类。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/**
 * 容器初始化的过程:BeanDefinition 的 Resource 定位、BeanDefinition 的载入、BeanDefinition 的注册。
 * BeanDefinition 的载入和 bean 的依赖注入是两个独立的过程,依赖注入一般发生在 应用第一次通过
 * getBean() 方法从容器获取 bean 时。
 *
 * 另外需要注意的是,IoC 容器有一个预实例化的配置(即,将 AbstractBeanDefinition 中的 lazyInit 属性
 * 设为 true),使用户可以对容器的初始化过程做一个微小的调控,lazyInit 设为 false 的 bean
 * 将在容器初始化时进行依赖注入,而不会等到 getBean() 方法调用时才进行
 */
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 调用容器准备刷新,获取容器的当前时间,同时给容器设置同步标识
        prepareRefresh();

        // 告诉子类启动 refreshBeanFactory() 方法,BeanDefinition 资源文件的载入从子类的 refreshBeanFactory() 方法启动开始
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 为 BeanFactory 配置容器特性,例如类加载器、事件处理器等
        prepareBeanFactory(beanFactory);

        try {
            // 为容器的某些子类指定特殊的 BeanPost 事件处理器
            postProcessBeanFactory(beanFactory);

            // 调用所有注册的 BeanFactoryPostProcessor 的 Bean
            invokeBeanFactoryPostProcessors(beanFactory);

            // 为 BeanFactory 注册 BeanPost 事件处理器.
            // BeanPostProcessor 是 Bean 后置处理器,用于监听容器触发的事件
            registerBeanPostProcessors(beanFactory);

            // 初始化信息源,和国际化相关.
            initMessageSource();

            // 初始化容器事件传播器
            initApplicationEventMulticaster();

            // 调用子类的某些特殊 Bean 初始化方法
            onRefresh();

            // 为事件传播器注册事件监听器.
            registerListeners();

            // 初始化 Bean,并对 lazy-init 属性进行处理
            finishBeanFactoryInitialization(beanFactory);

            // 初始化容器的生命周期事件处理器,并发布容器的生命周期事件
            finishRefresh();
        }

        catch (BeansException ex) {
            // 销毁以创建的单态 Bean
            destroyBeans();

            // 取消 refresh 操作,重置容器的同步标识.
            cancelRefresh(ex);

            throw ex;
        }
    }
}

obtainFreshBeanFactory() 方法告诉了子类去刷新内部的 beanFactory

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/**
 * Tell the subclass to refresh the internal bean factory.
 * 告诉子类去刷新内部的 beanFactory
 */
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // 自己定义了抽象的 refreshBeanFactory() 方法,具体实现交给了自己的子类 
    refreshBeanFactory();
    // getBeanFactory() 也是一个抽象方法,交由子类实现
    // 看到这里是不是很容易想起 “模板方法模式”,父类在模板方法中定义好流程,定义好抽象方法
    // 具体实现交由子类完成
    return getBeanFactory();
}

AbstractRefreshableApplicationContext 中对 refreshBeanFactory() 方法的实现。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
 * 在这里完成了容器的初始化,并赋值给自己私有的 beanFactory 属性,为下一步调用做准备
 * 从父类 AbstractApplicationContext 继承的抽象方法,自己做了实现
 */
protected final void refreshBeanFactory() throws BeansException {
    // 如果已经建立了 IoC 容器,则销毁并关闭容器
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        // 创建 IoC 容器,DefaultListableBeanFactory 类实现了 ConfigurableListableBeanFactory 接口
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        beanFactory.setSerializationId(getId());
        // 对 IoC 容器进行定制化,如设置启动参数,开启注解的自动装配等
        customizeBeanFactory(beanFactory);
        // 载入 BeanDefinition,在当前类中只定义了抽象的 loadBeanDefinitions() 方法,具体实现 调用子类容器
        loadBeanDefinitions(beanFactory);
        // 给自己的属性赋值
        this.beanFactory = beanFactory;
    } catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

AbstractXmlApplicationContext 中对 loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 的实现。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
 * 实现了基类 AbstractRefreshableApplicationContext 的抽象方法
 */
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // DefaultListableBeanFactory 实现了 BeanDefinitionRegistry 接口,在初始化 XmlBeanDefinitionReader 时
    // 将 BeanDefinition 注册器注入该 BeanDefinition 读取器
    // 创建用于从 Xml 中读取 BeanDefinition 的读取器,并通过回调设置到 IoC 容器中去,容器使用该读取器读取 BeanDefinition 资源
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    beanDefinitionReader.setEnvironment(this.getEnvironment());
    // 为 beanDefinition 读取器设置 资源加载器,由于本类的基类 AbstractApplicationContext
    // 继承了 DefaultResourceLoader,因此,本容器自身也是一个资源加载器
    beanDefinitionReader.setResourceLoader(this);
    // 设置 SAX 解析器,SAX(simple API for XML)是另一种 XML 解析方法。相比于 DOM,SAX 速度更快,占用内存更小。
    // 它逐行扫描文档,一边扫描一边解析。相比于先将整个 XML 文件扫描近内存,再进行解析的 DOM,SAX 可以在解析文档的
    // 任意时刻停止解析,但操作也比 DOM 复杂。
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    // 初始化 beanDefinition 读取器,该方法同时启用了 Xml 的校验机制
    initBeanDefinitionReader(beanDefinitionReader);
    // Bean 读取器真正实现加载的方法
    loadBeanDefinitions(beanDefinitionReader);
}

继续看 AbstractXmlApplicationContext 中 loadBeanDefinitions() 的重载方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
 * 用传进来的 XmlBeanDefinitionReader 读取器加载 Xml 文件中的 BeanDefinition
 */
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {

    /**
     * ClassPathXmlApplicationContext 与 FileSystemXmlApplicationContext 在这里的调用出现分歧,
     * 各自按不同的方式加载解析 Resource 资源,最后在具体的解析和 BeanDefinition 定位上又会殊途同归。
     */

    // 获取存放了 BeanDefinition 的所有 Resource,FileSystemXmlApplicationContext 类未对
    // getConfigResources() 进行重写,所以调用父类的,return null。
    // 而 ClassPathXmlApplicationContext 对该方法进行了重写,返回设置的值
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        // XmlBeanDefinitionReader 调用其父类 AbstractBeanDefinitionReader 的方法加载 BeanDefinition
        reader.loadBeanDefinitions(configResources);
    }
    // 调用父类 AbstractRefreshableConfigApplicationContext 的实现,
    // 优先返回 FileSystemXmlApplicationContext 构造方法中调用 setConfigLocations() 方法设置的资源
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        // XmlBeanDefinitionReader 调用其父类 AbstractBeanDefinitionReader 的方法从配置位置加载 BeanDefinition
        reader.loadBeanDefinitions(configLocations);
    }
}

AbstractBeanDefinitionReader 中对 loadBeanDefinitions 方法的各种重载及调用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/**
 * loadBeanDefinitions() 方法的重载方法之一,调用了另一个重载方法 loadBeanDefinitions(String)
 */
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
    Assert.notNull(locations, "Location array must not be null");
    // 计数器,统计加载了多少个BeanDefinition
    int counter = 0;
    for (String location : locations) {
        counter += loadBeanDefinitions(location);
    }
    return counter;
}

/**
 * 重载方法之一,调用了下面的 loadBeanDefinitions(String, Set<Resource>) 方法
 */
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
    return loadBeanDefinitions(location, null);
}

/**
 * 获取在 IoC 容器初始化过程中设置的资源加载器
 */
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
    // 在实例化 XmlBeanDefinitionReader 后 IoC 容器将自己注入进该读取器作为 resourceLoader 属性
    ResourceLoader resourceLoader = getResourceLoader();
    if (resourceLoader == null) {
        throw new BeanDefinitionStoreException(
                "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
    }

    if (resourceLoader instanceof ResourcePatternResolver) {
        try {
            // 将指定位置的 BeanDefinition 资源文件解析为 IoC 容器封装的资源
            // 加载多个指定位置的 BeanDefinition 资源文件
            Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
            // 委派调用其子类 XmlBeanDefinitionReader 的方法,实现加载功能
            int loadCount = loadBeanDefinitions(resources);
            if (actualResources != null) {
                for (Resource resource : resources) {
                    actualResources.add(resource);
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
            }
            return loadCount;
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "Could not resolve bean definition resource pattern [" + location + "]", ex);
        }
    }
    else {
        /**
         * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
         * AbstractApplicationContext 继承了 DefaultResourceLoader,所以 AbstractApplicationContext
         * 及其子类都会调用 DefaultResourceLoader 中的实现,将指定位置的资源文件解析为 Resource,
         * 至此完成了对 BeanDefinition 的资源定位
         * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
         */
        Resource resource = resourceLoader.getResource(location);
        // 从 resource 中加载 BeanDefinition,loadCount 为加载的 BeanDefinition 个数
        // 该 loadBeanDefinitions() 方法来自其实现的 BeanDefinitionReader 接口,
        // 且本类是一个抽象类,并未对该方法进行实现。而是交由子类进行实现,如果是用 xml 文件进行
        // IoC 容器的初始化,则调用 XmlBeanDefinitionReader 中的实现
        int loadCount = loadBeanDefinitions(resource);
        if (actualResources != null) {
            actualResources.add(resource);
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
        }
        return loadCount;
    }
}

resourceLoader 的 getResource() 方法有多种实现,看清 FileSystemXmlApplicationContext 的继承体系就可以明确,其走的是 DefaultResourceLoader 中的实现。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
 * 获取 Resource 的具体实现方法
 */
public Resource getResource(String location) {
    Assert.notNull(location, "Location must not be null");
    // 如果 location 是类路径的方式,返回 ClassPathResource 类型的文件资源对象
    if (location.startsWith(CLASSPATH_URL_PREFIX)) {
        return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
    }
    else {
        try {
            // 如果是 URL 方式,返回 UrlResource 类型的文件资源对象,
            // 否则将抛出的异常进入 catch 代码块,返回另一种资源对象
            URL url = new URL(location);
            return new UrlResource(url);
        }
        catch (MalformedURLException ex) {
            // 如果既不是 classpath 标识,又不是 URL 标识的 Resource 定位,则调用容器本身的
            // getResourceByPath() 方法获取 Resource。根据实例化的子类对象,调用其子类对象中
            // 重写的此方法,如 FileSystemXmlApplicationContext 子类中对此方法的重写
            return getResourceByPath(location);
        }
    }
}

/**
 * 实例化一个 FileSystemResource 并返回,以便后续对资源的 IO 操作
 * 本方法是在 DefaultResourceLoader 的 getResource() 方法中被调用的,
 */
@Override
protected Resource getResourceByPath(String path) {
    if (path != null && path.startsWith("/")) {
        path = path.substring(1);
    }
    return new FileSystemResource(path);
}

解析资源并封装

loadBeanDefinitions(String location, Set actualResources) 方法中调用了XmlBeanDefinitionReader中的loadBeanDefinitions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
 * XmlBeanDefinitionReader 加载资源的入口方法
 */
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    // 调用本类的重载方法,通过 new EncodedResource(resource) 获得的 EncodedResource 对象
    // 能够将资源与读取资源所需的编码组合在一起
    return loadBeanDefinitions(new EncodedResource(resource));
}

/**
 * 通过 encodedResource 进行资源解析,encodedResource 对象持有 resource 对象和 encoding 编码格式
 */
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.getResource());
    }

    Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
    if (currentResources == null) {
        currentResources = new HashSet<EncodedResource>(4);
        this.resourcesCurrentlyBeingLoaded.set(currentResources);
    }
    if (!currentResources.add(encodedResource)) {
        throw new BeanDefinitionStoreException(
                "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
    }
    try {
        // 从 resource 中获取输入流,对 resource 中的内容进行读取
        InputStream inputStream = encodedResource.getResource().getInputStream();
        try {
            // 实例化一个"XML 实体的单个输入源",将 inputStream 作为自己的属性
            InputSource inputSource = new InputSource(inputStream);
            // 如果 encodedResource 中的 encoding 属性不为空,就为 inputSource 设置读取 XML 的编码格式
            if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
            }
            // 这里是具体的读取过程
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
        }
        finally {
            // 关闭 IO 流
            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();
        }
    }
}

/**
 * 从指定 XML 文件中解析 bean,封装成 BeanDefinition 对象的具体实现
 */
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
    try {
        // 通过 documentLoader 获取 XML 文件的 Document 对象
        Document doc = doLoadDocument(inputSource, resource);
        // 启动对 BeanDefinition 的详细解析过程,该解析过程会用到 Spring 的 Bean 配置规则
        int count = registerBeanDefinitions(doc, resource);
        if (logger.isDebugEnabled()) {
            logger.debug("Loaded " + count + " bean definitions from " + resource);
        }
        return count;
    } 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);
    }
}

/**
 * 按照 Spring 对配置文件中 bean 元素的语义定义,将 bean 元素 解析成 BeanDefinition 对象
 */
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    // 得到 BeanDefinitionDocumentReader,将 xml 中配置的 bean 解析成 BeanDefinition 对象
    // BeanDefinitionDocumentReader 只是个接口,这里实际上是一个 DefaultBeanDefinitionDocumentReader 对象
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    // 获得容器中注册的 bean 数量
    int countBefore = getRegistry().getBeanDefinitionCount();
    // 解析过程入口
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    // 统计解析的 Bean 数量
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

文档解析器 DefaultBeanDefinitionDocumentReader 对配置文件中元素的解析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
  this.readerContext = readerContext;
  // 解析的具体实现
  doRegisterBeanDefinitions(doc.getDocumentElement());
}  


protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);
    if (this.delegate.isDefaultNamespace(root)) {
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource());
                }
                return;
            }
        }
    }
    // 前置解析处理,可以在解析 bean 之前进行自定义的解析,增强解析的可扩展性
    preProcessXml(root);
      // 从 Document 的根元素开始进行 Bean 定义的 Document 对象
    parseBeanDefinitions(root, this.delegate);
      // 后置解析处理,可以在解析 bean 之后进行自定义的解析,增加解析的可扩展性
    postProcessXml(root);

    this.delegate = parent;
} 


/**
 * 根据 Spring 的 bean解析规则,从 Document 的根元素开始进行解析
 */
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    // 根节点 root 是否使用了 Spring 默认的 XML 命名空间
    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;
                // 如果 ele 定义的 Document 的元素节点使用的是 Spring 默认的 XML 命名空间
                if (delegate.isDefaultNamespace(ele)) {
                    // 使用 Spring 的 bean解析规则 解析元素节点
                    parseDefaultElement(ele, delegate);
                }
                else {
                    // 若没有使用 Spring 默认的 XML 命名空间,则使用用户自定义的解析规则解析元素节点
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        // 若 Document 的根节点没有使用 Spring 默认的命名空间,则使用用户自定义的解析规则
        // 解析 Document 根节点
        delegate.parseCustomElement(root);
    }
}

/**
 * 使用 Spring 的 bean解析规则 解析 Spring元素节点
 */
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);
    }
    // 若元素节点既不是 <Import> 也不是 <Alias>,即普通的 <Bean> 元素,
    // 则按照 Spring 的 bean解析规则 解析元素
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    // 如果被解析的元素是 beans,则递归调用 doRegisterBeanDefinitions(Element root) 方法进行解析
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        doRegisterBeanDefinitions(ele);
    }
}

Spring对bean的解析过程不在这里进行分析了,详细见源码。这里主要看一下Spring是如何将解析后的bean注册进IOC容器的

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
 * 解析 bean 元素
 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

    // BeanDefinitionHolder 是对 BeanDefinition 的进一步封装,持有一个 BeanDefinition 对象 及其对应
    // 的 beanName、aliases别名。对 <Bean> 元素的解析由 BeanDefinitionParserDelegate 实现
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        // 对 bdHolder 进行包装处理
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            /**
             * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
             * 向 Spring IoC 容器注册解析完成的 BeanDefinition对象,这是 BeanDefinition 向 IoC 容器注册的入口
             * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
             */
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                    bdHolder.getBeanName() + "'", ele, ex);
        }
        // 在完成向 Spring IOC 容器注册 BeanDefinition对象 之后,发送注册事件
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}  


/**
 * 将解析到的 BeanDefinition对象 注册到 IoC容器
 */
public static void registerBeanDefinition(
        BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
        throws BeanDefinitionStoreException {

    // 获取解析的 <bean>元素 的名称 beanName
    String beanName = definitionHolder.getBeanName();
    /**
     * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     * 开始向 IoC容器 注册 BeanDefinition对象
     * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     */
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // 如果解析的 <bean>元素 有别名alias,向容器中注册别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String aliase : aliases) {
            registry.registerAlias(beanName, aliase);
        }
    }
} 

BeanDefinitionRegistry 中的 registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法在 DefaultListableBeanFactory 实现类中的具体实现。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

    /** 按注册顺序排列的 beanDefinition名称列表(即 beanName)  */
    private final List<String> beanDefinitionNames = new ArrayList<String>();

    /** IoC容器 的实际体现,key --> beanName,value --> BeanDefinition对象 */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);

    /**
     * 向 IoC容器 注册解析的 beanName 和 BeanDefinition对象
     */
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        // 校验解析的 BeanDefiniton对象
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        // 注册的过程中需要线程同步,以保证数据的一致性
        synchronized (this.beanDefinitionMap) {
            Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);

            // 检查是否有同名(beanName)的 BeanDefinition 存在于 IoC容器 中,如果已经存在,且不允许覆盖
            // 已注册的 BeanDefinition,则抛出注册异常,allowBeanDefinitionOverriding 默认为 true
            if (oldBeanDefinition != null) {
                if (!this.allowBeanDefinitionOverriding) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                            "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                            "': There is already [" + oldBeanDefinition + "] bound.");
                }
                // 如果允许覆盖同名的 bean,后注册的会覆盖先注册的
                else {
                    if (this.logger.isInfoEnabled()) {
                        this.logger.info("Overriding bean definition for bean '" + beanName +
                                "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                    }
                }
            }
            // 若该 beanName 在 IoC容器 中尚未注册,将其注册到 IoC容器中,
            else {
                // 将 beanName 注册到 beanDefinitionNames列表
                this.beanDefinitionNames.add(beanName);
                this.frozenBeanDefinitionNames = null;
            }
            // beanDefinitionMap 是 IoC容器 的最主要体现,他是一个 ConcurrentHashMap,
            // 直接存储了 bean的唯一标识 beanName,及其对应的 BeanDefinition对象
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        // 重置所有已经注册过的 BeanDefinition 的缓存
        resetBeanDefinition(beanName);
    }
}

BeanDefinition

在Spring中,BeanDefinition接口有多个实现类,如RootBeanDefinitionChildBeanDefinition等。这些实现类提供了具体的功能和扩展点。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class BeanDefinitionExample {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        reader.loadBeanDefinitions("beans.xml");

        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("exampleBean");

        System.out.println("Bean Class Name: " + beanDefinition.getBeanClassName());
        System.out.println("Scope: " + beanDefinition.getScope());
        System.out.println("Is Lazy Init: " + beanDefinition.isLazyInit());
        System.out.println("Factory Bean Name: " + beanDefinition.getFactoryBeanName());
        System.out.println("Factory Method Name: " + beanDefinition.getFactoryMethodName());
        System.out.println("Init Method Name: " + beanDefinition.getInitMethodName());
        System.out.println("Destroy Method Name: " + beanDefinition.getDestroyMethodName());
        System.out.println("Depends On: " + Arrays.toString(beanDefinition.getDependsOn()));
        System.out.println("Is Autowire Candidate: " + beanDefinition.isAutowireCandidate());
    }
}

核心属性

  1. beanClassName

    • 描述:Bean的全限定类名。
    • 用途:指示Spring IoC容器实例化bean时应使用的类。
  2. scope

    • 描述:Bean的作用域(如单例(singleton)、原型(prototype)等)。
    • 用途:定义bean的生命周期和可见性。
  3. lazyInit

    • 描述:指示是否应延迟初始化bean。
    • 用途:如果为true,bean将在首次访问时初始化,而不是在容器启动时初始化。
  4. primary

    • 描述:指示该bean是否是候选bean中的首选bean。
    • 用途:在注入时,如果存在多个候选bean,可以使用该属性标记首选bean。
  5. factoryBeanName

    • 描述:指定一个bean的名称,该bean将用作工厂来创建当前bean实例。
    • 用途:用于创建bean实例的工厂bean名称。
  6. factoryMethodName

    • 描述:指定工厂方法的名称,该方法将用于创建bean实例。
    • 用途:定义创建bean实例的工厂方法。
  7. initMethodName

    • 描述:指定bean初始化时要调用的方法名称。
    • 用途:在bean实例化并完成依赖注入之后调用。
  8. destroyMethodName

    • 描述:指定bean销毁时要调用的方法名称。
    • 用途:在容器关闭或bean销毁时调用。

依赖相关属性

  1. dependsOn
    • 描述:指定当前bean依赖的其他bean的名称。
    • 用途:确保在创建当前bean之前先创建这些依赖bean。
  2. autowireCandidate
    • 描述:指示该bean是否可作为其他bean自动装配的候选者。
    • 用途:控制bean是否可以被自动装配。
  3. propertyValues
    • 描述:包含该bean的所有属性值的集合。
    • 用途:用于设置bean的属性。
  4. constructorArgumentValues
    • 描述:包含该bean的构造函数参数值的集合。
    • 用途:用于构造函数注入。

高级属性

  1. parentName
    • 描述:指定当前bean定义的父bean定义。
    • 用途:用于bean定义继承。
  2. abstract
    • 描述:指示该bean定义是否是抽象的。
    • 用途:抽象bean定义不能被实例化,只能被继承。
  3. role
    • 描述:指示该bean定义的角色,可以是用户、支持或基础设施。
    • 用途:区分不同类型的bean定义。
  4. description
    • 描述:对bean的描述信息。
    • 用途:用于文档化目的。

总结

  1. 实例化一个ApplicationContext的对象;

  2. 刷新、初始化bean工厂;

  3. 调用bean工厂后置处理器完成扫描;

  4. 循环解析扫描出来的类信息;

  5. 实例化一个BeanDefinition对象来存储解析出来的类信息;

  6. 把实例化好的beanDefinition对象put到beanDefinitionMap当中缓存起来以便后面实例化bean;

1