目录
一、UML类图及核心组件分析
1.UML类图分析
2.核心组件关系
二、源码分析
前提说明,这个核心架构组成只是个人划分的,不代表官方意见,这样划分只是为了更方便的理解和分析Spring框架。
传送门:
- (二)Spring框架原理之实例化bean和@Autowired实现原理
一、UML类图及核心组件分析
1.UML类图分析
其关键的UML类图如下:
看起来稍微复杂了点,但如果按接口的继承关系和作用来划分,我们可以大致分为七个部分:
- BeanFactory部分:Spring工厂的基本接口,这部分包含了图中每个以BeanFactory结尾的类,其中我们使用的时候Spring工厂默认的会为我们创建一个DefaultListableBeanFactory类来当成Spring工厂,用来创建基本的Bean对象;
- AliasRegistry部分:这部分包含了AliasRegistry和BeanDefinitionRegistry,AliasRegistry的主要功能便是让加载的bean在Spring工厂中设置别名,而BeanDefinitionRegistry则是用来管理BeanDefinition对象的,这类对象是JavaBean未实例化之前存储在Spring工厂中的形态;
- SingletonBeanRegistry部分:这部分的作用便是用来实例化和存储单例Bean;
- BeanFactoryPostProcessor部分:这部分的主要作用是对BeanFactory中的值进行某些操作,或者去加载处理某些类,将这些类转换成BeanDefinition,基本上所有的这类接口处理的对象结果都是BeanDefinition,随后再将这些BeanDefinition通过getBean方法实例化成bean返回;
- BeanPostProcessor部分:这部分便是在调用getBean方法实例化流程中对Bean对象进行操作的接口,存储在bean工厂中,对这个bean进行的任何操作都将最终返回;
- ApplicationEventMulticaster部分:这部分的作用便是Spring框架实现的监听广播功能,这部分经常被使用在监听Spring框架执行流程或完成某些特定功能,但主要还是用来监听Spring启动流程;
- ApplicationContext部分:这部分是Spring的上下文,这里面将会保存前面的所有部分(如果这个的实现类需要这些内容的话),同时这部分也控制着Spring的执行流程,Spring工厂的刷新以及前面几个部分的调用便是在这里面完成。
2.核心组件关系
核心组件关系图如下:
核心组件的关系和上面的UML类图分析差不多,DefaultListableBeanFactory是Spring上下文默认提供的一个Spring工厂,这个工厂对象实现了三个管理Bean的最高接口,Spring刷新流程中获得的BeanDefinition和JavaBean等都是存储在这个对象中的。
或许看到这里会有疑问,Spring实现的功能及拓展性这么好,为什么只有这么几个核心组件?其实Spring实现的很多功能都是通过这几个组件去扩展的,使用几个基本的抽象实现,利用模板模式让子类重写子类方法,在子类中增加额外的功能,经过Spring的一步一步迭代,便形成了现在Spring的体量以及灵活度。
这里举几个例子来说明Spring一些常用的功能是如何通过这几个核心组件完成功能扩展的:
- @Autowired自动注入注解的实现,这个注解依赖的便是BeanPostProcessor接口,其具体的实现类为AutowiredAnnotationBeanPostProcessor,在初始化Bean的时候Spring将会在这个实现类中去判断各个方法和字段是否被@Autowired注解了,如果有则进行一系列判断,再循环调用getBean,将获得的bean赋值到这个方法返回值或字段上;
- @Configuration及相关配套的接口注解读取,其依赖的便是BeanFactoryPostProcessor接口实现类ConfigurationClassPostProcessor,这个类中将会调用其它的Reader、Parser类去读取与其配套使用的@Bean等注解和接口;
- 又如最开始使用Spring在XML配置文件配置<component-scan/>标签来扫描具体的包,这个处理类便是以AbstractRefreshableApplicationContext为入口,调用loadBeanDefinitaion方法,随后调用XMLReader类,调用进NamespaceHandler进而处理<component-scan/>标签里面配置的包路径,把这些包路径下的bean扫描注册进Spring工厂。
二、源码分析
此次源码分析只是分析Spring最关键refresh方法及涉及到的成员对象,对Spring形成一个总体认识,并不会对整个流程进行分析。
这个类是ApplicationContext这一系列最高的抽象实现类,只介绍大致流程,其关键源码如下:
public abstract class AbstractApplicationContext
extends DefaultResourceLoader
implements ConfigurableApplicationContext {
// 父级Spring上下文
private ApplicationContext parent;
// 上下文中存储的环境变量
private ConfigurableEnvironment environment;
// 存储BeanFactoryPostProcessor的集合对象
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors=
new ArrayList<>();
// 发布时间广告的对象
private ApplicationEventMulticaster applicationEventMulticaster;
// 程序监听器集合
private final Set<ApplicationListener<?>> applicationListeners =
new LinkedHashSet<>();
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备刷新上下文前的准备,记录刷新开始时间,以及初始化资源属性
// 在这里面将会把closed设置为false,active设置为true
prepareRefresh();
// 方法中也是两个空的方法,具体的实现是交给子类完成,原来的Spring框架
// 和Tomcat集成时根据XML配置的扫描路径便是在这个方法中完成的
ConfigurableListableBeanFactory beanFactory =
obtainFreshBeanFactory();
// 刷新前对bean工厂进行准备处理,如添加一些必要的BeanPostProcessor
prepareBeanFactory(beanFactory);
try {
// 在准备完bean工厂后执行的操作,子类一般的操作也是为其添加一些
// 额外的BeanPostProcessor对象,或者利用扫描器扫描包下的bean
postProcessBeanFactory(beanFactory);
// 调用bean工厂中的BeanFactoryPostProcessor对象,这里面将会完成
// 所有BeanFactoryPostProcessor对象的处理
invokeBeanFactoryPostProcessors(beanFactory);
// 将前面通过扫描的beanPostProcessor注册进bean工厂
// 我们自己写的beanPostProcessor将会在这里被注册进工厂中
registerBeanPostProcessors(beanFactory);
// 为上下文初始化MessageSource对象,这个对象的作用是国际化
// 当使用跨国语言或者多国语言程序时将被使用到(自己还未用过)
initMessageSource();
// 初始化ApplicationEventMulticaster对象,如果未指定类型则是
// SimpleApplicationEventMulticaster,指定了则按指定的来
initApplicationEventMulticaster();
// 当前面的beanPostProcessor和beanFactoryPostProcessor都准备
// 好之后,子类可重写这个方法来完成刷新中的自定义操作
// 如Springboot内嵌的ApplicationContext中就在这个方法中
// 创建Tomcat对象以便后续使用
onRefresh();
// 为前面的SimpleApplicationEventMulticaster对象注册监听器
registerListeners();
// 用来实例化bean工厂中所有非延迟加载的未实例化单例对象
finishBeanFactoryInitialization(beanFactory);
// 最后一步,将会发布ContextRefreshedEvent时间以及调用一些
// 生命周期执行器,当然子类也可以执行一些扫尾操作,如Springboot
// 在前面的onRefresh中创建了Tomcat对象,在这个重写方法中将会
// 启动运行Tomcat
finishRefresh();
} catch (BeansException ex) {
// 清除bean工厂中缓存的单例对象
destroyBeans();
// 设置active标签为false,代表Spring工厂未活动
cancelRefresh(ex);
// 抛出异常
throw ex;
} finally {
// 将注解、映射、解析类型工具类和类加载器的缓存清空
resetCommonCaches();
}
}
}
}
看完源码后可能有人会奇怪,不是说BeanPostProcessor也会在这里面吗?怎么没看到这个成员变量?其实是因为BeanPostProcessor系列对象是存储在beanFactory中的,在Spring工厂中实例化的时候将会直接调用BeanPostProcessor集合对象对Bean对象进行处理。
如果对BeanPostProcessor和BeanFactoryPostProcessor等接口的实现有兴趣可以去看一下(一)Spring关键接口之通用可自定义接口文章。