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()。在核心逻辑的前后,各定义了一个模板方法,交由子类进行定制化的处理。