Spring5源码解析系列一——IoC容器核心类图

基本概念梳理

IoC(Inversion of Control,控制反转)就是把原来代码里需要实现的对象创建、依赖,反转给容器来帮忙实现。我们需要创建一个容器,同时需要一种描述来让容器知道要创建的对象与对象的关系。这个描述最具体的表现就是我们所看到的配置文件。

DI(Dependency Injection,依赖注入)就是指对象被动接受依赖类而不自己主动去找,换句话说,就是指对象不是从容器中查找它依赖的类,而是在容器实例化对象时主动将它依赖的类注入给它。

撇开Spring源码不看,从我们自身的理解出发,如果我们来开发这样的容器,需要考虑下面几个问题:

  • 对象与对象的关系怎么表示?

答案:可以用XML、Properties等语义化的配置文件来表示。

  • 描述对象关系的文件存放在哪里?

答案:可以是Classpath、FileSystem、URL网络资源或者servletContext等。

  • 不同的配置文件对对象的描述不一样,如标准的、自定义声明式的,如何统一?

答案:这就可能在内部需要有一个统一的关于对象的定义,所有外部的描述都必须转化成统一的描述定义。

  • 如何对不同的配置文件进行解析?

答案:需要对不同的配置文件语法采用不同的解析器。

Spring核心容器类图

1、BeanFactory

Spring中Bean的创建是典型的工厂模式,这一系列的Bean工厂,即IoC容器,为开发者管理对象之间的依赖关系提供了很多便利和基础服务,在Spring中有许多IoC容器的实现供用户选择,其相互关系如下图所示。

其中,BeanFactory作为最顶层的一个接口类,定义了IoC容器的基本功能范围,BeanFactory有三个重要的子类:ListableBeanFactory、
HierarchicalBeanFactory和AutowireCapableBeanFactory。但是从类图中我们可以发现最终的默认实现类是DefaultListableBeanFactory,它实现了所有的接口。那么为何要定义这么多层次的接口呢?查阅这些接口的源码和说明发现,每个接口都有它的使用场合,主要是为了区分在Spring内部操作过程中对象的传递和转化,对对象的数据访问所做的限制。

例如,ListableBeanFactory接口表示这些Bean可列表化,而HierarchicalBeanFactory表示这些Bean 是有继承关系的,也就是每个Bean 可能有父 Bean。AutowireCapableBeanFactory 接口定义Bean的自动装配规则。这三个接口共同定义了Bean的集合、Bean之间的关系及Bean行为。最基本的IoC容器接口是BeanFactory,来看一下它的源码:

查看代码

 package org.springframework.beans.factory;

import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;


public interface BeanFactory {

    //对FactoryBean的转义定义,因为如果使用Bean名字来进行搜索FactoryBean的话得到的只是工厂生成的对象
	//如果需要得到工厂本身,需要转义
	String FACTORY_BEAN_PREFIX = "&";


	//根据Bean的名字获得在IoC容器种的Bean的实例
	Object getBean(String name) throws BeansException;

	//根据Bean的名字和Class类型来得到Bean的实例,同时增加了类型安全验证机制
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

	
	Object getBean(String name, Object... args) throws BeansException;

	
	<T> T getBean(Class<T> requiredType) throws BeansException;

	
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	
	<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

	
	<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

	//提供对Bean的检索,看下具备Bean的名字的Bean是否存在于IoC容器中
	boolean containsBean(String name);

	//判断具备name的Bean是否存在于容器,并且是否是单例
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	//判断具备name的Bean是否存在于容器,并且是否是原型
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	
	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	//得到Bean实例的Class类型
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	
	@Nullable
	Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;

	//得到Bean实例在IoC容器中的别名,当然你输入别名来搜索,结果原名也会包含其中
	String[] getAliases(String name);

}

从上面可以看出,在BeanFactory里只对IoC容器的基本行为做了定义,根本不关心你的Bean是如何定义及怎样加载的。正如我们只关心能从工厂里得到什么产品,不关心工厂是怎么生产这些产品的。要知道工厂是如何产生对象的,我们需要看具体的IoC容器实现,Spring里面提供了许多IoC容器实现,比如GenericApplicationContext、ClasspathXmlApplicationContext等。

PS:ApplicationContext是Spring提供的一个高级的IoC容器,它除了能够提供IoC容器的基本功能,还为用户提供了以下附加服务。

  1. 支持信息源,可以实现国际化(实现MessageSource接口)。
  2. 访问资源(实现ResourcePatternResolver接口,后面系列会讲到)。
  3. 支持应用事件(实现ApplicationEventPublisher接口)。

2、BeanDifinition

Spring IoC容器管理我们定义的各种Bean对象及其相互关系,Bean对象在Spring实现中是以BeanDefinition来描述的,其继承体系如下图所
示。

3、BeanDefinitionReader

Bean的解析过程非常复杂,功能被分得很细,因为这里需要被扩展的地方很多,必须保证足够的灵活性,以应对可能的变化。Bean的解析
主要就是对Spring配置文件的解析。这个解析过程主要通过BeanDefinitionReader来完成,看看Spring中BeanDefinitionReader的类结构图,如下图所示。

总结

通过前面的分析,我们对Spring框架体系有了一个基本的宏观了解,希望可以好好理解,最好在脑海中形成画面,为后面的学习
打下良好的基础。