本文转载自微信公众号《苏三说技术》。作者因为热爱所以坚持ing。转载本文请联系苏三硕科技公众号。前言中最近写的春季系列的几篇文章得到了很多读者的好评,也有读者希望我多写这方面的文章。甚至有读者私信我,问我如何阅读spring源码。为此,我打算写一个spring源码解读系列来回馈一直以来支持我的fans。不知道大家有没有这样的经历:想看spring的源码,却无从下手。spring源码太多了,看的时候就丢了。不知道哪些是主要的,哪些是次要的。前几天还记得,今天忘记了。spring的源码非常复杂。说实话,这种文章不好写。很难解释清楚。写的篇幅会很长。读者可能没有耐心看完,看完后很容易忘记。我打算采用图文结合的方式,去掉糟粕,只解读部分精华,让读者在阅读源码时思路清晰,不至于迷失方向。另外,最重要的是,看完之后可以记住很多关键的流程。在spring庞大的系统中,IOC(inversionofcontrol)贯穿始终,其作用不言而喻。下面先从IOC入手,介绍一下它的主要流程,给有需要的朋友一些指导。入门spring容器的顶层接口是:BeanFactory,但是我们更多的使用它的子接口:ApplicationContext。通常情况下,如果我们想手动初始化通过xml文件配置的spring容器,代码是这样的:你想手动初始化通过配置类配置的spring容器,代码是这样的:AnnotationConfigApplicationContextapplicationContext=newAnnotationConfigApplicationContext(Config.class);Useruser=(User)applicationContext.getBean("name");这两个类应该是最常见的入门了,但是却殊途同归。最后会调用refresh方法,这才是spring容器初始化的真正入口。顺便说一下,其实调用refresh方法的不止这两个类。我们整体来看一下:虽然调用refresh方法的类非常多,但是我还是决定以ClassPathXmlApplicationContext类为例给大家讲解一下,因为够经典,难度也相对较小。重申一下,由于spring源码庞大,就算我一次能看完,恐怕你也没有那么多耐心看完。所以我会采用你好我的方式,忽略一些细节,只关注重点。如果有同学对某些细节比较感兴趣,欢迎加我微信与我交流,或者关注我的后续文章,我会详细讲解。refresh方法refresh方法是springioc的真正入口,负责初始化spring容器。既然这个方法的作用是初始化spring容器,为什么这个方法叫init呢?答案很简单,因为它不会只被调用一次。springboot的SpringAppication类中的run方法会调用refreshContext方法,会调用一次refresh方法。springcloud的BootstrapApplicationListener类中的onApplicationEvent方法会调用SpringApplication类中的run方法。刷新方法也会被调用一次。这也是为什么在springboot项目中引入springcloud会调用两次refresh方法的原因。springmvc的FrameworkServlet类中的initWebApplicationContext方法会调用configureAndRefreshWebApplicationContext方法,会调用一次refresh方法,但是会提前判断容器是否激活。所以这里refresh就是重建的意思。好了,别再瞎扯了。下面重点说一下刷新的关键步骤:其实上图中的方法一眼看上去好像很多,但真正核心的方法并不多。主要讲最重要的几个:obtainFreshBeanFactoryinvokeBeanFactoryPostProcessorsregisterBeanPostProcessorsfinishBeanFactoryInitialization解析xml配置文件obtainFreshBeanFactory方法会解析xml的bean配置,生成一个BeanDefinition对象注册到spring容器中(说白了就是在很多地图集)。经过几层调用(不说细节,很简单),会转到AbstractBeanDefinitionReader类的loadBeanDefinitions方法:这个方法会循环locations(applicationContext.xml文件路径),调用另一个loadBeanDefinitions方法,并逐个分析文件。经过一系列的操作,location会转化为inputSource和resource,再转化为Document对象进行解析。解析xml文件时,需要判断是默认标签还是自定义标签。处理逻辑不同:spring默认的标签只有4个:
