Spring源码深度解析(二)
Spring源码深度解析(二)
一. 主要内容
- BeanFactory体系设计
- 核心接口
- BeanDefinition加载流程
- 设计思想总结
二. BeanFactory体系设计
BeanFactory是Spring中十分重要的接口,也是Spring IOC容器的顶级接口。它基于工厂模式,定义了最基本的IOC容器的功能,如获取Bean实例、查看Bean的类型和查看Bean是否存在等:
在BeanFactory的基础上扩展了很多接口,每个接口都有各自的功能。BeanFactory的继承体系如下:
三. 各种BeanFactory
- ListableBeanFactory:可以根据条件列出Bean的清单
- AutowireCapableBeanFactory:提供了Bean自动注入的支持。
- HierarchicalBeanFactory:提供了容器继承的支持,可以维护一个parentBeanFactory父容器的引用,并通过它获取到父容器中的Bean。
- ConfigurableBeanFactory:可对BeanFactory进行各种配置
- DefaultListableBeanFactory:BeanFactory的默认实现,实现了上述所有接口的功能,是BeanFactory的集大成者。
- XmlBeanFactory:DefaultListableBeanFactory的子类,继承了DefaultListableBeanFactory的所有功能,并在此基础上扩展了XML文件相关的定制化处理。
可以看出,Spring很好地贯彻了面向接口编程的原则,几乎所有的重要的类上面都定义了接口。而且,通过接口的继承,可以灵活地扩展出不同功能的接口。
四. 核心接口
- BeanDefinition:对一个Bean实例的描述,包括其类型、属性、构造器、依赖等。 之前看过一个比喻:BeanFactory相当于一个汽车制造工厂,Bean对应于工厂中造出的各种车,而BeanDefinition就是每种车的图纸,描述了车的品牌、型号、所需零件、性能参数等。
- BeanDefinitionRegistry:BeanDefinition注册中心,定义了对 BeanDefinition 的各种增删改操作。
- AliasRegistry:别名注册中心。Spring支持为一个Bean定义多个别名。
- SingletonBeanRegistry:单例Bean注册中心。Spring会缓存所有Singleton类型的Bean,每次获取到的都是同一个。 BeanDefinition在定义了Bean的Scope,常用的有Singleton和Prototype,还可以扩展Scope接口进行自定义。 String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
- Resource:Spring对底层资源的封装,抽象了所有Spring内部可以使用到的底层资源,并提供了一些相关的查询和操作方法
对于不同来源的Resource,Spring都提供了对应的实现类,常用的有文件系统资源FileSystemResource和类路径资源ClassPathResource等。
五. BeanDefinition加载流程解析
BeanDefinition加载是Spring最重要的一个步骤,只有加载了所有定义的BeanDefinition后,才能根据其创建指定Bean,注入依赖,并完成后续一系列功能。BeanDefinition加载是在容器启动时自动完成的。
书中以XmlBeanFactory为例,讲解了BeanDefinition的加载和注册流程。虽然现在都以注解方式定义Bean,XML文件方式很少使用,但两种方式只是BeanDefinition的来源不同,核心处理流程是类似的,因此仍然以书中的内容为准。至于注解方式加载BeanDefinition的流程,如果感兴趣可以看下AnnotationConfigApplicationContext类。
XmlBeanFactory加载BeanDefinition的流程大致可以分为三个核心步骤:
- 资源的定位
- 将资源文件的解析为BeanDefinition集合
- 将解析好的BeanDefinition注入到容器中
六. 资源定位
可以显式指定BeanDefinition所在资源的位置,如书中代码所示:
Resource resource = new ClassPathResource("applicationContext.xml");
XmlBeanFactory beanFactory = new XmlBeanFactory(resource);
这样显式Resource的方式省去了资源定位的步骤,但是,实际上没有这么用的,现在使用的都是ApplicationContext接口,其加载资源的处理在AbstractRefreshableApplicationContext#refreshBeanFactory()中,后面章节有具体叙述。
七. BeanDefinition解析
不管基于何种方式,现在拿到了BeanDefinition所在的资源文件Resource,则创建XmlBeanFactory,执行BeanDefinition解析的工作。
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
//加载配置文件
this.reader.loadBeanDefinitions(resource);
}
XmlBeanFactory在维护了一个XmlBeanDefinitionReader实例,其功能就是从XML配置文件中解析出BeanDefinition。XmlBeanDefinitionReader是BeanDefinitionReader接口的实现类,BeanDefinitionReader接口的作用就是解析BeanDefinition。
解析过程中的核心类:
- XmlBeanFactory:XML形式的Bean工厂。
- XmlBeanDefinitionReader:负责从XML配置文件中读取BeanDefinition。
- DocumentLoader:专注于XML解析,将执行的XML文件解析成一个Document对象。
- BeanDefinitionDocumentReader:针对DocumentLoader解析好的Document,从中加载出BeanDefinition,并注册到容器中。
- BeanDefinitionParserDelegate:BeanDefinitionDocumentReader内部维护的委托对象,创建BeanDefinition实例并对其进行包装。
- BeanDefinitionReaderUtils:最终执行实际的BeanDefinition的注册。
XmlBeanFactory并没有自己完成BeanDefinition解析的工作,而是委托给各种不同的类去处理,每个类只关注一项具体的功能,这也是单一职责原则的很好的体现。
加载BeanDefinition流程:
八. BeanDefinition注册
九. 设计思想总结
- 工厂模式
- 面向接口编程
- 单一职责原则
- 策略模式:BeanDefinitionReader的作用是读取BeanDefinition。根据BeanDefinition的来源不同,Spring定义了不同的实现类(XmlBeanDefinitionReader、GroovyBeanDefinitionReader、PropertiesBeanDefinitionReader),并在相应的BeanFactory处指定了具体的实现类(XmlBeanFactory指定使用XmlBeanDefinitionReader)。
- 模板方法模式:参见DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions()方法:
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
//BeanDefinitionParserDelegate代理对象,主要用于BeanDefinition的解析与注册
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
//profile属性处理,只解析满足当前profile的BeanDefinition
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);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
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;
}
}
}
//解析前置处理,模板方法,留给子类实现
preProcessXml(root);
//实际的BeanDefinition解析与注册
parseBeanDefinitions(root, this.delegate);
//解析前置处理,模板方法,留给子类实现
postProcessXml(root);
this.delegate = parent;
}
- 在父类方法中定义了方法的整体流程,并给出了核心实现parseBeanDefinitions()。在核心逻辑的前后,各定义了一个模板方法,交由子类进行定制化的处理。
- 我的WCF之旅(3):在WCF中实现双工通信
- 我的WCF之旅 (11): 再谈WCF的双向通讯-基于Http的双向通讯 V.S. 基于TCP的双向通讯
- 更新弹幕系统的心得体会
- 我的WCF之旅(6):在Winform Application中调用Duplex Service出现TimeoutException的原因和解决方案
- 我的WCF之旅 (11): 再谈WCF的双向通讯-基于Http的双向通讯 V.S. 基于TCP的双向通讯
- 我的WCF之旅(6):在Winform Application中调用Duplex Service出现TimeoutException的原因和解决方案
- 扩展mysql - 手把手教你写udf
- scrapy初体验 - 安装遇到的坑及第一个范例
- Linux性能监控 - CPU、Memory、IO、Network
- 浅谈UDP(数据包长度,收包能力,丢包及进程结构选择)
- WCF版的PetShop之三:实现分布式的Membership和上下文传递
- “高并发”问题如何解决?腾讯云一分钟配置的“黑科技”帮您
- 初探JavaScript(三)——JS带我"碰壁"带我飞
- 初探JavaScript(四)——作用域链和声明提前
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释