目录
prepareBeanFactory(beanFactory) 方法
postProcessBeanFactory(beanFactory) 方法
invokeBeanFactoryPostProcessors(beanFactory) 方法
registerBeanPostProcessors(beanFactory) 方法
initApplicationEventMulticaster() 方法
finishBeanFactoryInitialization(beanFactory) 方法
Spring IoC源码学习全系列
Spring IoC源码学习:ApplicationContext 刷新前的配置
Spring IoC源码学习:obtainFreshBeanFactory详解
Spring IoC源码学习:parseDefaultElement详解
Spring IoC源码学习:parseCustomElement详解
Spring IoC源码学习:context:component-scan 节点详解
Spring IoC源码学习:invokeBeanFactoryPostProcessors详解
Spring IoC源码学习:registerBeanPostProcessors详解
Spring IoC源码学习:finishBeanFactoryInitialization详解
Spring IoC源码学习:createBean详解(上)
Spring IoC源码学习:createBean详解(下)
Spring IoC源码学习:finishRefresh 详解
Spring 作为现在最优秀的框架之一,被广泛的应用于 Java 项目中,但是大多数人都只知道如何使用,而不知其中的原理。对大多数人来说可能知道如何使用已经足够了,但是对于想提升自己的人来说,学习 Spring 的源码是一个不错的选择。在过去的几个月里,我利用空闲时间将IoC 的相关源码学习了一下,按照老习惯准备整理成笔记,以博文的形式记录下来,供自己以后使用,也供其他网友参考。由于涉及到的代码较多,因此会以一个系列的形式来呈现。
本系列文章只能作为学习 Spring IoC 源码中的一个参考,强烈不建议只看本系列的文章,而不自己去阅读 Spring 的源码。
注:本系列的博文基于版本:4.3.12.RELEASE,由于个人水平有限,因此文中难免有错误的地方,欢迎各位积极提出。
另外,在写文章的同时,可能自己会有新的认识,因此本系列文章可能会有不断的优化调整。
由于IoC 的代码量太大,要把完整的代码逻辑全部详细讲一遍比较费精力,因此本系列的文章会有取舍,以下内容会粗略带过或者舍弃。
1. 日常开发基本不会用到,并且对源码全局的理解不会造成明显的影响。
2. 比较过时的用法,已经有更好的用法。
3. 过于简单的代码(一眼就能看出意思)。
1.以 IDEA 为例,首先到Git上下载某个RELEASE 版本的 Spring 源码压缩包:Spring 源码地址,并解压到本地磁盘中。
2.New -> Project from Existing Sources
3.找到源码解压的地址,选中并点击 OK
4.选择 Import project from external model,并选中Gradle,然后点击 Next,之后一路默认即可,如果有需要选择的,选择Yes。
5.导入之后需要一段时间来构建索引,最后完成之后如下。
这边再聊个小事情。17年初,我当时正在准备跳槽,有一次面试的时候,一个面试官问我:你觉得学习源码有什么好处?对于当时的我来说,学习源码不过是为了应付面试。到现在,我对这个问题有了一些新的想法,我目前感觉到的主要好处有:
· 深入学习过源码后,自己在使用的时候显得更游刃有余。
· 可以学习到一些优秀的代码,无论是一些逻辑上的思路,还是仅仅是编码风格。
· 许多中间件都会基于 Spring 的扩展功能来实现,阅读 Spring 源码,能帮助你更好的阅读中间件源码。
· 最后还是应付面试。
学习Spring 源码不同于学习 JDK 源码,以前学习 JDK 源码基本就纯看源码,但是Spring 源码太多了,你纯看的话可能会无法很好的理解。以下几个点,可以帮助你更好的学习 Spring 源码。
1. 保持耐心,Spring 源码很多,想在短时间内就看透是很难的,需要保持持续性和耐心,一点点的去啃。
2. 可以通过 Debug Spring 源码的方式来帮助自己更好的理解。这边可以新建一个只有基础框架的空项目,然后根据自己的需要增加一些测试类。
3. 代码是最好的注释。Spring 作为最优秀的框架之一,其代码质量必然不用担心。因此,除了注释外,我们还可以通过类名、方法名、变量名、打印的日志来帮助我们理解。
4. 由于逻辑比较复杂,因此在执行一个操作时可能会有一个很长的调用链,最终进行实际操作的方法,一般会以 do 为方法的前缀。例如:对于创建 bean 实例来说,最终执行创建的方法为:doCreateBean;对于加载 bean 定义,最终执行加载的方法为:doLoadBeanDefinitions。
5. 如果某些代码看了很多遍还是无法很好的理解,可以到网上搜下别人的文章参考,如果没有合适的参考,可以先放着,先往后看,也许等你把后面的流程看了,你在回过头来看就理解了。因为有很多地方是前后相关联的,只看前面的是无法很好理解的。
6. 最重要的一点:反复看,反复看。Spring 的源码是一个大工程,想要一遍两遍就吃透就基本不可能的,只有反复的看、反复的推敲才能逐渐的加深自己的理解。
IoC 即 Inversion of Control,也就是控制反转。在传统的程序设计,我们直接在对象内部通过 new 来创建对象,是程序主动去创建依赖对象;而在Spring 中有专门的一个容器来创建和管理这些对象,并将对象依赖的其他对象注入到该对象中,这个容器我们一般称为 IoC 容器。
所有的类的创建、销毁都由 Spring 来控制,也就是说控制对象生存周期的不再是引用它的对象,而是Spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被 Spring 控制,所以这叫控制反转。
Spring 初始化的入口在 ContextLoaderListener,如果你的项目用了 Spring,通常可以在 web.xml 中找到下面这行代码。
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
ContextLoaderListener 是实现了 javax.servlet.ServletContextListener接口的服务器端程序,随 web 应用的启动而启动,只初始化一次,随 web 应用的停止而销毁。在web应用启动的时候会调用 contextInitialized 方法,停止的时候会调用contextDestroyed 方法。
从ContextLoaderListener 类为出发点,跟着下面的调用过程:
ContextLoaderListener.contextInitialized(ServletContextEvent event) -> initWebApplicationContext(event.getServletContext()); ContextLoader.initWebApplicationContext(ServletContext servletContext) -> configureAndRefreshWebApplicationContext(cwac, servletContext); ContextLoader.configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) -> wac.refresh(); AbstractApplicationContext.refresh()
我们最终来到了AbstractApplicationContext.java 里的 refresh() 方法,这个方法就是构建整个 IoC 容器过程的完整代码,只要把这个方法里的每一行代码都了解了,基本上了解了大部分 Spring 的原理和功能。
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
用于“刷新”和“销毁”的同步监视器,说白了就是一个锁。
为刷新准备新的上下文环境,设置其启动日期和活动标志以及执行一些属性的初始化。主要是一些准备工作,不是很重要的方法,可以先不关注。
用于获得一个新的 BeanFactory。
该方法会解析所有 Spring 配置文件(通常我们会放在 resources 目录下),将所有 Spring 配置文件中的 bean 定义封装成BeanDefinition,加载到 BeanFactory 中。常见的,如果解析到<context:component-scan base-package="com.joonwhee.open" /> 注解时,会扫描base-package 指定的目录,将该目录下使用指定注解(@Controller、@Service、@Component、@Repository)的bean 定义也同样封装成 BeanDefinition,加载到 BeanFactory 中。
上面提到的“加载到 BeanFactory 中”的内容主要指的是以下3个缓存:
· beanDefinitionNames缓存:所有被加载到 BeanFactory 中的 bean 的beanName 集合。
· beanDefinitionMap缓存:所有被加载到 BeanFactory 中的 bean 的beanName 和 BeanDefinition 映射。
· aliasMap缓存:所有被加载到 BeanFactory 中的 bean 的beanName 和别名映射。
prepareBeanFactory(beanFactory) 方法
配置beanFactory 的标准上下文特征,例如上下文的 ClassLoader、后置处理器等。这个方法会注册3个默认环境bean:environment、systemProperties 和systemEnvironment,注册 2 个 bean 后置处理器:ApplicationContextAwareProcessor 和ApplicationListenerDetector。
postProcessBeanFactory(beanFactory) 方法
允许子类对BeanFactory 进行后续处理,默认实现为空,留给子类实现。
invokeBeanFactoryPostProcessors(beanFactory) 方法
实例化和调用所有 BeanFactoryPostProcessor,包括其子类BeanDefinitionRegistryPostProcessor。
BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory时对外暴露的扩展点,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。
BeanDefinitionRegistryPostProcessor 继承自BeanFactoryPostProcessor,比 BeanFactoryPostProcessor 具有更高的优先级,主要用来在常规的 BeanFactoryPostProcessor 激活之前注册一些 bean定义。特别是,你可以通过 BeanDefinitionRegistryPostProcessor 来注册一些常规的 BeanFactoryPostProcessor,因为此时所有常规的 BeanFactoryPostProcessor 都还没开始被处理。
注:这边的“常规 BeanFactoryPostProcessor” 主要用来跟BeanDefinitionRegistryPostProcessor 区分。
registerBeanPostProcessors(beanFactory)方法
注册所有的BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。
BeanPostProcessor 接口是 Spring 初始化 bean时对外暴露的扩展点,Spring IoC 容器允许 BeanPostProcessor 在容器初始化 bean 的前后,添加自己的逻辑处理。在这边只是注册到 BeanFactory 中,具体调用是在 bean 初始化的时候。
具体的:在所有 bean 实例化时,执行初始化方法前会调用所有 BeanPostProcessor 的postProcessBeforeInitialization 方法,执行初始化方法后会调用所有BeanPostProcessor 的 postProcessAfterInitialization 方法。
初始化消息资源 MessageSource。
initApplicationEventMulticaster() 方法
初始化应用的事件广播器 ApplicationEventMulticaster。
该方法为模板方法,提供给子类扩展实现,可以重写以添加特定于上下文的刷新工作,默认实现为空。
注册监听器。
finishBeanFactoryInitialization(beanFactory)方法
该方法会实例化所有剩余的非懒加载单例 bean。除了一些内部的 bean、实现了BeanFactoryPostProcessor 接口的 bean、实现了BeanPostProcessor 接口的 bean,其他的非懒加载单例 bean 都会在这个方法中被实例化,并且 BeanPostProcessor 的触发也是在这个方法中。
完成此上下文的刷新,主要是推送上下文刷新完毕事件(ContextRefreshedEvent )到监听器。
上文标红的方法为构建 IoC 构成中最重要的4个方法,简单的描述就是:
· obtainFreshBeanFactory 创建一个新的 BeanFactory、读取和解析 bean 定义。
· invokeBeanFactoryPostProcessors 提供给开发者对 BeanFactory 进行扩展。
· registerBeanPostProcessors 提供给开发者对 bean 进行扩展。
· finishBeanFactoryInitialization 实例化剩余的所有非懒加载单例 bean。