目录
- 1 工程创建
- 2 ClassPathResource实例化
- 3 XmlBeanFactory实例化
- 3.1 XmlBeanDefinitionReader实例化
- 3.2 调用loadBeanDefinitions方法
- 3.2.1 核心处理方法 doLoadBeanDefinitions
- 3.2.1.1 DefaultBeanDefinitionDocumentReader的registerBeanDefinitions方法
- 3.2.1.1.1 doRegisterBeanDefinitions(Element root)方法
- 3.2.1.1.1.1 delegate.parseBeanDefinitionElement(ele)
- 3.2.1.1.1.2 delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)
- 3.2.1.1.1.3 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())
- 3.2.1.1.1.4 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder))
- 4 详细流程图
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实例化
- 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