spring源码详细总结

前言

上周线上项目出了一个bug,使用WebMvcConfigurer和WebMvcConfigurationSupport不能同时使用,要不然WebMvcConfigurer能扫描到容器中,但是他的方法不能执行。

只有搞懂了spring的源码流程,才能对这个问题进行整体的把握。

ApplicationContext简介

通过debug的方式对spirng源码进行一步一步的解读,spring的核心之一就是IOC容器,这是一个抽象的概念,对应IOC,做过spirng开发的想必都有所耳闻,但是对于他是什么大部分初级程序员是不明朗的。

IOC体现在spring中就是ApplicationContext,这是最重要的接口,spirng中有众多的类实现了这个接口,不同的ApplicationContext在不同的应用场景使用。

AnnotationConfigApplicationContext是基于注解的方式启动容器,ClassPathXmlApplicationContext是基于xml配置的方式启动容器,其他还有许多的方式启动容器,虽然多,但是能够见名知意,名字都是**ApplicationContext。
spring-ioc容器核心启动类继承关系
类名有个简单的印象就行,如果都看一遍太枯燥了,笔者也不推荐这样做。

Beanfactory简介

BeanFactory我的理解就是IOC容器中的一些工具方法,这是我浅显的理解,下图是BeanFactory 的所有方法,ApplicationContext继承了这个接口。
Beanfactory全部方法

启动过程

通过debug的方式一步步深挖spring源码,一定要自己debug要不然很累!一定要自己debug要不然很累!一定要自己debug要不然很累!重要事情说三遍。

先通过一个简单的样例,看下spring-ico的一个简单使用。这个方法的作用就是new了一个ApplicationContext传入一个定义的bean,然后通过getBeanDefinitionNames()获取到它的容器中所有的bean。
在这里插入图片描述
在这里插入图片描述
点进去ApplicationContext的构造方法,会发现它调用了一个refresh()方法,这个方法是spring-ico最核心的方法,IOC初始化、注册bean等等一系列方法都是这这里完成的。

值得一提的是,springboot的run方法一步步点进去调用的还是这个refresh方法,看到这相信大家对于spirng和springboot的关系有了一个模糊的认识。
springboot-run方法
透过现象看本质,其实springboot的核心启动方法还是调用了spring的run方法,只是在这个方法的前后又做了一些启动的事,增强了spring而已。

书归正传,让我们重新回到refresh方法中一步步的解读。在refresh上面打上一个断点,一步一步看每一个方法都做了什么事。
spring-IOC核心方法refresh()
高能预警:下面是一段超长的源码分析,可能引起不适,但是对于技术的提高也是显著的。

@Override
public void refresh() throws BeansException, IllegalStateException {
// 加锁,避免 refresh() 启动和销毁容器混乱this.startupShutdownMonito该锁为当前对象。
synchronized (this.startupShutdownMonitor) {

  // 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
  prepareRefresh();

  // 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中,
  // 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了,
  // 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map)
  **ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();**

  // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
  // 这块待会会展开说
  prepareBeanFactory(beanFactory);

  try {
     // 【这里需要知道 BeanFactoryPostProcessor 这个知识点,Bean 如果实现了此接口,
     // 那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。】

     // 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化
     // 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事
     postProcessBeanFactory(beanFactory);
     // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
     invokeBeanFactoryPostProcessors(beanFactory);

     // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
     // 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
     // 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化
     registerBeanPostProcessors(beanFactory);

     // 国际化
     initMessageSource();

     // 初始化当前 ApplicationContext 的事件广播器
     initApplicationEventMulticaster();

     // 从方法名就可以知道,典型的模板方法(钩子方法),
     // 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
     onRefresh();

     // 注册事件监听器,监听器需要实现 ApplicationListener 接口。
     registerListeners();

     // 初始化所有的 singleton beans
     //(lazy-init 的除外)
     finishBeanFactoryInitialization(beanFactory);

     // 最后,广播事件,ApplicationContext 初始化完成
     finishRefresh();
  }

     // Destroy already created singletons to avoid dangling resources.
     // 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
     destroyBeans();

     // 把异常往外抛
     throw ex;
  }

  finally {
     // Reset common introspection caches in Spring's core, since we
     // 重置缓存
     resetCommonCaches();
  }

}
}

以上就是refresh()方法概述,如果全部展开来讲的话会很长很长,接下来会分很多文章来解读每一个方法的源码,但是读者要对它的所有方法做到心中有数。

spring与其他框架的整合,都蕴含在这些方面中,充分利用了spring的扩展性。

总结

在花了一天时间后,这篇文章终于算是基本写完了,应该透过现象看本质,去理解 Spring 写得好的地方,去理解它的设计思想。

充分解读spring代码量真的比较大,分支旁路众多。以后会逐步拆解它的每一个问题,敬请期待吧。

posted @ 2021-12-27 14:04  程序员田同学  阅读(930)  评论(0编辑  收藏  举报
博客主的头像