spring源码解析-容器的基本实现

1 工程创建

1.打开idea,选择菜单 Flie—>New—>Project,弹出对话框,如下图所示:

在这里插入图片描述

2.输入项目名:springDemo

在这里插入图片描述

3.完成后,添加maven依赖

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.0.8.RELEASE</version>
</dependency>

4.在main目录下创建目录resources目录,将resources文件夹设置为资源根目录

在这里插入图片描述

5.添加spring配置文件applicationContext.xml

在这里插入图片描述

6.添加bean相关配置

<bean id="testBean" class="bean.TestBean"/>

在这里插入图片描述

7.创建测试bean

package bean;
//bean 的定义
public class TestBean {
    private String testStr = "testStr";

    public String getTestStr() {
        return testStr;
    }
    public void setTestStr(String testStr) {
        this.testStr = testStr;
    }
}

在这里插入图片描述

8.创建入口main方法

package org.example;
import bean.TestBean;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

public class  Demo
{
    public static void main( String[] args )
    {
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        TestBean testBean = beanFactory.getBean(TestBean.class);
        System.out.println(testBean.getTestStr());
    }
}

在这里插入图片描述

2 ClassPathResource实例化

  1. ClassPathResource是org.springframework.core.io.Resource接口的实现类。可以使用ClassLoader或Class类加载资源。支持转换为java.io.File对象(在Jar文件中的资源除外)。通过这个类,可以读取到指定classpath下路径的文件内容。

在这里插入图片描述

2.重要字段含义:
private ClassLoader classLoader;// 通过ClassLoader加载资源文件
private Class<?> clazz; // 通过Class类加载资源文件

3.ClassPathResource实例化后的属性:

在这里插入图片描述

3 XmlBeanFactory实例化

在这里插入图片描述

3.1 XmlBeanDefinitionReader实例化

作用:XmlBeanDefinitionReader是BeanDefinitionReader三大读取器的其中一个,XmlBeanDefinitionReader是为了读取Xml文件中的Bean而设计出来的。可以将Resource对象解析为Document对象。XmlBeanDefinitionReader继承于AbstractBeanDefinitionReader。AbstractBeanDefinitionReader内部有registry成员属性,理所当然可以往IOC容器里面添加BeanDefinition。XmlBeanDefinitionReader继承于AbstractBeanDefinitionReader,必定也能将BeanDefinition注册到容器里面。

在这里插入图片描述

3.2 调用loadBeanDefinitions方法

XmlBeanDefinitionReader调用loadBeanDefinitions方法,参数为2中实例化的ClassPathResource
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2.1 核心处理方法 doLoadBeanDefinitions

此处调用doLoadDocument方法的目的:使用 DefaultDocumentLoader 将 Resource 转换为 Document 对象

在这里插入图片描述
1. doLoadDocument方法

使用 DefaultDocumentLoader 解析转换文档。getValidationModeForResource 获取XML的验证模式(DTD 和 XSD)

在这里插入图片描述

1.1 DefaultDocumentLoader的loadDocument方法
在这里插入图片描述

2 registerBeanDefinitions方法
根据返回的 Document 注册 Bean 信息。通过registerBeanDefinitions(doc, resource)方法实现。
在这里插入图片描述

2.1 使用 createBeanDefinitionDocumentReader 实例化 DefaultBeanDefinitionDocumentReader

BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();

2.2 使用BeanDefinitionRegistry的子类DefaultListableBeanFactory,通过getBeanDefinitionCount()方法获取已经注册的BeanDefinition 的个数。

int countBefore = getRegistry().getBeanDefinitionCount();
在这里插入图片描述

2.3 通过DefaultBeanDefinitionDocumentReader加载及注册bean

documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

2.4 返回本次加载的BeanDefinitions数量

return getRegistry().getBeanDefinitionCount() - countBefore;

3.2.1.1 DefaultBeanDefinitionDocumentReader的registerBeanDefinitions方法

获取 root 节点,将root作为参数继续BeanDefinition的注册。

在这里插入图片描述

3.2.1.1.1 doRegisterBeanDefinitions(Element root)方法

首先是对 profile 属性的处理,然后进行 document 的解析。
在这里插入图片描述
//解析前处理,留给子类实现,模板方法模式
preProcessXml(root);
//调用 parseBeanDefinitions 方法进行 document 的解析。
parseBeanDefinitions(root, this.delegate);
//解析后处理,留给子类实现
postProcessXml(root);

1 parseBeanDefinitions方法
调用 parseBeanDefinitions 方法进行 document 的解析。首先判断是默认标签还是自定义标签。通过delegate.isDefaultNamespace判断根节点是否是默认命名空间(使用 node.getNamespaceURI() 获取名称空间,并与Sping中规定的命名空间http://www.springframework.org/schema/beans比较)。如果是默认的调用parseDefaultElement(ele, delegate)方法,如果是自定义的调用delegate.parseCustomElement(ele)方法。按图中所示,root是根节点也就是beans。parseDefaultElement(ele, delegate);是对默认标签的解析,普通的import、alias、bean等。按照示例,则是<bean id="testBean"class=“bean.TestBean”/>。delegate.parseCustomElement是解析自定义的标签。比如采用tx定义命名空间、jdbc命名等等。

在这里插入图片描述
在这里插入图片描述
对节点<bean id="testBean" class="bean.TestBean"/>进行处理

在这里插入图片描述

1.1 processBeanDefinition方法(重点分析)
在Spring配置文件中,比较核心、常见的就是通过bean标签定义Bean,同时最复杂的也是processBeanDefinition,代码如下:
在这里插入图片描述

3.2.1.1.1.1 delegate.parseBeanDefinitionElement(ele)

1 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
此步操作返回BeanDefinitionHolder对象。BeanDefinitionHolder是BeanDefinition的封装类,封装了BeanDefinition,bean的名字和别名,用它来完成向IOC容器的注册。形参为元素和解析器,该方法通过元素节点和解析器创建BeanDefinitionHolder,这里要注意,在创建BeanDefinitionHolder时就已经创建了BeanDefinition并封装到了BeanDefinitionHolder内部,所以下面直接传BeanDefinitionHolder就可以对BeanDefinition进行赋值了。

在这里插入图片描述

1.1 parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean)
此方法主要作用:
bean标签具体解析内容:id、name和多个name名称、别名alias、beanName唯一性检查,生成beanDefinition(实际上是GenericBeanDefinition生成),beanName是否命名等步骤,最后使用生成的beanDefinition来封装BeanDefinitionHolder实例。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

checkNameUniqueness:beanName唯一性检查:

在这里插入图片描述

1.2 parseBeanDefinitionElement(ele, beanName, containingBean)方法内部(核心):
 
Spring采用硬编码的方式对bean标签进行处理,分别使用了以下八个核心点来处理,如下所示:
//①使用GenericBeanDefinition来生成AbstractBeanDefinition实例
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//②spring内置处理bean属性的硬编码处理逻辑
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
//③解析元数据
parseMetaElements(ele, bd);
//④解析lookup-method
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//⑤解析replaced-method
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//⑥解析构造函数参数
parseConstructorArgElements(ele, bd);
//⑦解析property子元素
parsePropertyElements(ele, bd);
//⑧解析qualifier子元素
parseQualifierElements(ele, bd);

在这里插入图片描述
在这里插入图片描述

1.2.1 createBeanDefinition(className, parent)方法

在这里插入图片描述
在这里插入图片描述

1.2.2 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd) 方法
spring内置处理bean属性的硬编码处理逻辑,包括:singleton、scope、abstract、lazy、autowire、depends_on、autowire_candidate、primary、init_method、destroy_method、factory_method和factory_bean,具体代码:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3.2.1.1.1.2 delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)

判断bdHolder对象不为空时会判断是否存在子节点,持续解析
在这里插入图片描述

3.2.1.1.1.3 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())

1 registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)

此步操作的目的是将bdHolder注册到容器中。方法形参是上面刚创建的BeanDefinitionHolder和一个BeanDefinitionRegistry。BeanDefinitionRegistry是封装在readerContext中的一个注册器接口,由DefaultListableBeanFactory实现。DefaultListableBeanFactory 是 BeanDefinitionRegistry接口的实现类。也就是当初创建的Ioc容器本身,该容器实现了BeanDefinitionRegistry的接口,提供了注册的方法registerBeanDefinition。

在这里插入图片描述

1.1 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.2 registry.registerAlias(beanName, alias)
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3.2.1.1.1.4 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder))

发送事件通知,通知相关的监听器,表明bean加载完毕。
在这里插入图片描述

4 详细流程图

链接:https://www.processon.com/view/link/6347ef1f6376891c6b55ddbc

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值