1、spring源码解析之概况流程
文章目录
- 概要
- 1.程序入口:加载配置类
- 2.注解配置上下文AnnotationConfigApplicationContext
- 3.刷新上下文
- 4.核心类AnnotationConfigApplicationContext的类图结构
- 5.跟踪源码进入ioc
概要
以前总是很忙,没有时间写博客,现在挤出时间写一些总结性及实用性的博客。
首先聊一下,之所以开始看源码,是因为随着自身对java的理解不断加深,感觉自己对技术架构方面很感兴趣。所以想深入了解一下开源框架的本质,看各种开源框架、jdk源码有一段时间了,也在源码上写了很多自己理解的注释,一直没有整体总结,偶尔想起来有一些思路,但是容易忘记,所以想做一些总结,每一个我觉得非常复杂的核心流程,我都会用一张或时许图、流程图来进行学习总结。
总的来说,spring的总体流程不是很复杂,但是细思极恐;每一个类、每一个方法的内部实现能牵扯出很多与之相关联的类;其中实现错综复杂,不过不管怎么难,带着设计模式的思想、以及多思考,多实践,多总结的角度,多看几遍,终归会有所收获(可以自己手绘一些uml时序图、流程图来加深理解)。
本文及后续文章主要基于spring 5.0源码分析spring 核心的 ioc和aop,首先缕清spring运行的整体脉络流程。由于注解驱动(无xml)的流行,本文不会涉及xml的上下文及容器刷新流程(注意:作者之前有使用过ssm,涉及过xml配置,个人觉得xml配置会让人思想上更容易理解spring容器、bean的定义等等,感觉现在直接使用spring boot的人可能渐渐忽略了spring才是基石)。
1.程序入口:加载配置类
本文主要采用AnnotationConfigApplicationContext 作为程序的起点。
public class MyApplication {public static void main(String[] args) {//spring上下文,启动一个spring应用程序。AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyApp.class);Car bean =(Car) context.getBean("car");System.out.println(bean.getColor()+bean.getPrice());}
}
2.注解配置上下文AnnotationConfigApplicationContext
AnnotationConfigApplicationContext:注解配置上下文。
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {//this()由于继承关系,所以会先调用父类的构造方法,在调用子类的构造方法/*** @Author coyhzx* @Description 类继承结构(暂不涉及接口)DefaultResourceLoader -> AbstractApplicationContext ->GenericApplicationContext -> AnnotationConfigApplicationContext* {@link DefaultResourceLoader} 初始化当前线程的classLoader* {@link AbstractApplicationContext} 初始化资源模式匹配解析器 PathMatchingResourcePatternResolver* {@link GenericApplicationContext} 初始化 ioc底层容器 DefaultListableBeanFactory* {@link AnnotationConfigApplicationContext} 初始化 reader 注解的bean的读取器,scanner 类路径的bean的扫描器**/this();//componentClasses 注册单个组件beanregister(componentClasses);//刷新容器refresh();}
AnnotationConfigApplicationContext的无参构造this();
public AnnotationConfigApplicationContext() {//创建一个注解的bean的读取器,猜想一下,很关键,要想读取注解,是不是要注册一些内置的BeanPostProcess后置处理器来处理注解bean。this.reader = new AnnotatedBeanDefinitionReader(this);//创建一个类路径的bean的扫描器this.scanner = new ClassPathBeanDefinitionScanner(this);}
3.刷新上下文
refresh()刷新容器
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.// 刷新上下文前的准备prepareRefresh();// Tell the subclass to refresh the internal bean factory.// 获取beanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.// beanFactory的一些准备工作prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.// 留给子类Context去实现,目前为空postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.// 调用 beanFactoryPostProcessors beanFactory的后置处理器//重点: 解析入口的配置类invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.//注册Bean的后置处理器registerBeanPostProcessors(beanFactory);// Initialize message source for this context.//初始化消息源initMessageSource();// Initialize event multicaster for this context.//初始化事件广播监听器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.//子类初始化一些特殊的beanonRefresh();// Check for listener beans and register them.// 检查并注册监听器registerListeners();// Instantiate all remaining (non-lazy-init) singletons.//重点:完成所有非延迟加载bean的初始化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();}}}
简单来说:整体流程其实已经走完了,感觉有点走马观花,但是其中每一个方法每一个new对象,每一个父子继承的实现其实很复杂。得慢慢梳理。先看一下AnnotationConfigApplicationContext得类图,从图中可以看成,spirng把一个上下文的接口抽象出来了很多顶级接口,和抽象类和实现类,看多了很多源码,摸清楚了一些spring框架的一些小特点,通常spring接口会有顶级接口,定义规范,抽象类实现接口的公用方法,具体的特性交给不同实现类去实现,这里着重介绍一些核心得关键接口和类。
4.核心类AnnotationConfigApplicationContext的类图结构
BeanFactory: Bean工厂的顶级接口。里面定义了变量factorbean的前缀&,getBean()、getType()、是否单例、是否原型的方法等等。
ResourceLoader: 资源加载的顶级接口。很简单,里面仅仅定义了classpath的url,getClassLoader()、getResource(String location)方法。
DefaultResourceLoader:默认的资源加载类。加载classpath下的资源文件。
AbstractApplicationContext:抽象的上下文类。实现了可配置的上下文接口ConfigurableApplicationContext,是一个很重要的类,refresh()刷新容器的主要逻辑就在其中。
GenericApplicationContext:广泛普通的上下文类。我们真正底层的ioc容器,bean工厂DefaultListableBeanFactory就是在它的初始化中创建的。
AnnotationConfigApplicationContex:注解配置的上下文类。很关键,是可以直接定位加载注解配置类的上下文。
BeanDefinitionRegistry:bean的注册接口。定义了注册bean、移除bean等接口。
5.跟踪源码进入ioc
先简单的介绍AnnotationConfigApplicationContext#register(componentClasses)方法,以及跟踪源码,可以直接进入我们常说的ioc容器之中,看着上下文是如何帮我们在上下文中创建一个BeanDefinition,并放入容器中。
好了,尽管我省略了很多细节,但是整体的配置类BeanDefinition注册流程通过下图展示,spring在ioc容器中注册了bean的定义了,那么如何去完成实例化bean的实例呢,请期待我下一篇文章把!
下一篇:2、spring源码解析之单例bean的实例化
1、spring源码解析之概况流程相关推荐
- Spring源码解析【完整版】--【bilibili地址:https://www.bilibili.com/video/BV1oW41167AV】
[本文为bilibili视频雷丰阳的Spring源码解析的完整版总结文章,其中文章前面大部分为他人博文的搬运,后面补充了其未总结的部分] 一.Java的注解 1. 注解的概念 注释:用文字描述程序,给 ...
- Spring源码解析之-- 事务TransactionInterceptor 分析(开启事务)
目录 一.介绍 二.TransactionInterceptor 分析 2. 流程 2.1 invoke 2.1.1 TransactionAspectSupport#invokeWithinTran ...
- Spring源码——声明式事务流程
前言 最近回顾了一下Spring源码,准备用思维导图的方式简单的将整个源码内容的流程展示出来,思维导图.图片等文件更新在https://github.com/MrSorrow/spring-frame ...
- Spring源码解析之@Component注解的扫描
阅读须知 Spring源码版本:4.3.8 文章中使用/* */注释的方法会做深入分析 正文 承接Spring源码解析之context:component-scan标签解析,下面就是扫描的流程: Cl ...
- Spring源码解析 - AbstractBeanFactory 实现接口与父类分析
2019独角兽企业重金招聘Python工程师标准>>> 我们先来看类图吧: 除了BeanFactory这一支的接口,AbstractBeanFactory主要实现了AliasRegi ...
- Spring源码解析:自定义标签的解析过程
2019独角兽企业重金招聘Python工程师标准>>> spring version : 4.3.x Spring 中的标签分为默认标签和自定义标签两类,上一篇我们探究了默认标签的解 ...
- Retrofit2源码解析——网络调用流程(下)
Retrofit2源码解析系列 Retrofit2源码解析(一) Retrofit2源码解析--网络调用流程(上) 本文基于Retrofit2的2.4.0版本 implementation 'com. ...
- android 输入法如何启动流程_android输入法02:openwnn源码解析01—输入流程
android 输入法 02:openwnn 源码解析 01-输入流程 之后要开始 android 日文输入法的测试,因此现在开始研究 android 输入法.之前两 篇文章已经对 android 自 ...
- Spring 源码解析 -- SpringWeb过滤器Filter解析
简介 在上几篇文章中探索了请求处理相关的代码,本篇开始探索请求处理前的一些操作代码,如Filter.本篇探索Filter初始化.请求处理等相关代码. 前言 说先简单的定义相关的测试代码: 启动类: i ...
- Spring源码解析 -- SpringWeb请求参数获取解析
Spring源码解析 – SpringWeb请求参数获取解析 简介 在文章:Spring Web 请求初探中,我们看到最后方法反射调用的相关代码,本篇文章就探索其中的参数是如何从请求中获取的 概览 方 ...
最新文章
- 1120. Friend Numbers (20)
- 相互靠近的色环电感之间的互感
- 210328卡式水分开阶段总结
- 5 个最受人喜爱的开源 Django 包
- 打砖块小游戏php程序,利用原生js实现html5打砖块小游戏(代码示例)
- oracle排名怎么去除空值影响,Oracle排序中null值处理方法讲解
- 1107: 回文数猜想(函数专题)
- 编写react组件_如何编写第一个React.js组件
- PHP--金额数字转换成英文
- python sqlite row
- 向量范数证明例题_第八课:向量的范数
- c#转换XML文件和json对象
- HTML5 Canvas vs. SVG vs. div
- 数据结构与算法中的经典算法
- ip地址块的聚合,计算其聚合后的可用地址数
- html设计判断闰年,javascript如何判断是否为闰年?
- C#——初识Console
- 字节跳动校招提前批前端一面总结
- HHUOJ 1395 彩票
- 男人二十岁后应该学会的习惯 - 褪墨