Spring源码里开天辟地的五个Bean,再介绍一个学习方法
准备工作
首先咱们还是来写一个最简单的例子:
用的还是 https://github.com/xiexiaojing/yuna 里的代码,只是标签和引用都换成了Spring原生的。
配置类就是配置了扫描路径:
在可以被扫描的包路径下定义了一个Bean对象。用了Component注解这里就可以理解为Bean对象了。
运行成功,通过Spring的IoC容器成功的获取了UserService的Bean对象,并调用了其test方法。
在《把对象交给spring管理的3种方法及经典应用》中我提到Spring有5个开天辟地的Bean。还列出了怎么通过SpringBoot的debug去找。这里其实在debug日志里就能看到把它们打印出来了:
大家不要忽略启动日志,读懂启动日志能获得很多信息,今天咱们就把这段启动日志Spring相关的部分分析透。
Spring启动日志第一行
org.springframework.context.annotation.AnnotationConfigApplicationContext
-
Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5bfbf16f
上面是Spring日志的第一行,翻译成中文就是刷新注解配置应用上下文。咱们来看源码:
进入这个实例化方法中看Spring的源码:
共三行,咱们来解读一下:
this初始化方法,里面初始化的后面都要用到,用到的时候再看,这一行可以忽略。剩余两行,一行作用是注册Bean的定义,另外一行是完成Bean的定义。
先时候注册Bean的定义。什么叫Bean的定义呢。如果Bean是一个产品,那Bean定义就是它的规格说明书。就是一个文档说明,这时候Bean还没有开始创建。注册Bean定义还有一种通过扫描来实现的方式:
这时候进入Spring注解配置应用上下文的实例化方法变成这个:
第二行register方法变成scan方法,其他没有变化,这说明scan方法和register方法完成了两种的功能。就是BeanDefinition。scan的原理我在《手撕spring核心源码,彻底搞懂spring流程》里详细讲过,这就和之前的内容对上了。
创建的事情要交给Bean工厂,也就是refresh方法要做的事情。
其实Bean工厂能不能完成Bean的创建等生命周期管理呢?可以。咱们的测试例子也可以这么写:
我直接用Bean工厂创建一个Bean也能实现。那ApplicationContext应用上下文与BeanFactory的区别在哪里呢?
BeanFactory可以理解为一个汽车工厂,它就是生产汽车的。 别人需要告诉他汽车怎么生产,看我例子里BeanDeclaration实际有很多参数需要我来添上,我展开给大家看看:
ApplicationContext 可以理解为汽车4s店。他提供一条龙服务。我只需要告诉他,我需要哪个汽车,其他都不需要管了。4s店自己帮我处理好。
咱们来看refresh方法,synchronized是多线程同步的,不需要管。第一个运行的方式是prepareRefresh。
进入这个方法就找到了第一行日志打印的地方:
咱们来看prepareRefresh主要做的4件事情:
1、初始化占位符属性的资源
2、检验所有必需的属性都是可解析的
3、存储应用监听器或者应用监听器半成品
4、初始化应用事件半成品
这四件事情不是本文的核心内容仅做了解。其实这四件事情对下文没有任何推动作用,这就是源码存在太多细枝末节,容易干扰视线的原因。所以要带着明确的目的去看。
Spring启动日志第二行
org.springframework.beans.factory.support.DefaultListableBeanFactory
-
Creating
shared
instance
of
singleton
bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
这是Spring开天辟地的五个Bean中的第一个。类型是
ConfigurationClassPostProcessor
它是一个BeanFactory的后置处理器,因此它的主要功能是参与BeanFactory的建造,在这个类中,会解析加了@Configuration的配置类,还会解析@ComponentScan、@ComponentScans注解扫描的包,以及解析@Import等注解。
找一行日志打印的位置有点困难,咱们用debug的方式找到哪一行打印的。最终定位在这里:
下面咱们站在上帝视角重新回到refresh方法:
refresh的前面都是在组建Bean工厂,从533行也就是内部会打印咱们这条日志的这一行开始调用Bean工厂后置处理器。Bean工厂后置处理器与Bean后置处理器不是一回事。Bean工厂后置处理器的作用就是前面Bean工厂组建完成,现在可以把组建好的Bean工厂传给这个后置处理器。后置处理器自己可以决定要对Bean工厂做些什么。
因为最重要的方法都在这里面,咱们直接来看
PostProcessorRegistrationDelegate
里面做了什么
日志是从标红的那行代码打印的,这是触发实现了高优先级的
BeanDefinitionRegistryPostProcessor
进行实例化并注册成后置处理的类。从这里咱们可以得出结论:Spring给它排了很高的优先级,对于Spring默认来说配置类解析器是最先被加载的后置处理器。
Spring启动日志第三行
org.springframework.context.annotation.ClassPathBeanDefinitionScanner
-
Identified
candidate
component
class:
file [D:\yuna\target\classes\com\brmayi\yuna\newspring\UserService.class]
这是验证用户bean是否符合要求的,可debug查看不详细解释。
Spring其他4个开天辟地的Bean
其他的由于方法相同,这里只介绍其他4个Bean的作用:
EventListenerMethodProcessor和 DefaultEventListenerFactory
DefaultEventListenerFactory是一个Bean工厂,
EventListenerMethodProcessor 是 Bean工厂的一个后置处理器, 用来对 @EventListener 提供支持。
AutowiredAnnotationBeanPostProcessor
使用Spring 编程时,使用Ioc,我们只需要声明对象,而由Spring 替我门自动注入,
而其中起重要作用则为
AutowiredAnnotationBeanPostProcessor,
它在bean实例化后,进行这重要的初始化操作。
CommonAnnotationBeanPostProcessor
这个Bean后置处理器通过继承
InitDestroyAnnotationBeanPostProcessor
对@ javax.annotation.PostConstruct
和@ javax.annotation.PreDestroy
注解的支持。以及依据bean name依赖注入的
@javax.annotation.Resource支持。
总结
本文介绍了使用查日志所在位置的方式学习源码。这种方式在文中我也特意举例说明了容易被带偏,偏离重心,要做好时间和学习规划,才能达到好的效果。
学习Spring不是一件容易的事,我之前学习的时候放弃过很多次。这期间不断变换学习方法重新学。最终突然达到了“蓦然回首”的顿悟。从此再看Spring都不是事儿。
从那之后再也不会因为手欠升级了某个版本或者删除了某些理论上不相关的依赖,程序运行不起来各种尝试才搞定。而变成了遇到问题,呆呆的想上一小会,定位一段源码验证一下猜想,做个简单的调整就搞定了。
假期哪里也去不了,在家看了一些过去的高分电影。很多电影反映了一些底层贫苦人民暗无天日的生活,一直到最后,他们的生活仍然没有一丝希望。咱们现在可能会经历一些小的痛苦,比如学Spring就很苦,但是这是带着希望的苦。喝下之后就像咖啡一样回味悠远~
Spring源码里开天辟地的五个Bean,再介绍一个学习方法相关推荐
- 源码解析:Spring源码解析笔记(五)接口设计总览
本文由colodoo(纸伞)整理 QQ 425343603 Java学习交流群(717726984) Spring解析笔记 启动过程部分已经完成,对启动过程源码有兴趣的朋友可以作为参考文章. 源码解析 ...
- Spring 源码解读第七弹!bean 标签的解析
Spring 源码解读继续. 本文是 Spring 系列第八篇,如果小伙伴们还没阅读过本系列前面的文章,建议先看看,这有助于更好的理解本文. Spring 源码解读计划 Spring 源码第一篇开整! ...
- 小米面试官:说说Spring源码里面的Bean的生命周期!
1. Bean的实例化概述 前一篇分析了BeanDefinition的封装过程,最终将beanName与BeanDefinition以一对一映射关系放到beanDefinitionMap容器中,这一篇 ...
- Spring 源码解析(四):bean的加载
//spring.xml 文件解析BeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring.xml&quo ...
- Spring源码深度解析(五):Spring AOP原理及源码详解
前言 OOP表示面向对象编程,是一种编程思想:AOP表示面向切面编程,也是一种编程思想,AOP的概念可以参考文章:SpringAOP基本概念详解. 正文 1.AbstractAdvisorAutoPr ...
- Spring源码深度解析(郝佳)-学习-Bean Id 获取
首先上图,我们要获取类PropertySourcesPlaceholderConfigurer的id属性值 AbstractBeanDefinitionParser.java protected St ...
- Spring 源码解析 - Bean创建过程 以及 解决循环依赖
一.Spring Bean创建过程以及循环依赖 上篇文章对 Spring Bean资源的加载注册过程进行了源码梳理和解析,我们可以得到结论,资源文件中的 bean 定义信息,被组装成了 BeanDef ...
- 面试有没有看过spring源码_如何看Spring源码、Java每日六道面试分享,打卡第二天...
原标题:如何看Spring源码.Java每日六道面试分享,打卡第二天 想要深入的熟悉了解Spring源码,我觉得第一步就是要有一个能跑起来的极尽简单的框架,下面我就教大家搭建一个最简单的Spring框 ...
- Spring源码解析:自定义标签的解析过程
2019独角兽企业重金招聘Python工程师标准>>> spring version : 4.3.x Spring 中的标签分为默认标签和自定义标签两类,上一篇我们探究了默认标签的解 ...
最新文章
- java excel导出 jxl_java使用JXL导出Excel及合并单元格
- linux 快捷matlab_Linux命令 笔记(一)
- javascript 入门事件的
- [USACO1.2]双重回文数 Dual Palindromes
- Android 开发技能图谱
- 通过QUIC 0-RTT建立更快的连接
- 数据结构——最小生成树之prime算法(与最短路径之迪杰斯特拉算法很像)
- Vivado Design Suite用户指南之约束的使用第二部分(约束方法论)
- php采集绕过cloudflare,关于pyspider绕过CloudFlare验证的问题
- bzoj 3495: PA2010 Riddle(2-SAT)
- lambda,reserve list, list comprehension, string of slice
- c语言编程学习宝典,C语言学习宝典app
- 桌面计算机图标带虚线框,桌面图标出现虚线框,win10桌面图标带有虚线方框
- cad批量选择相同块_在CAD中如何快速选择相同或类似的图形、图块?
- c++ 0x3f 0x3f3f 0x3f3f3f 0x3f3f3f3f的具体值
- SourceTree Push 代码报错:remote: Support for password authentication was removed on April 26, 2022....
- mac升级node版本(用n升级nodejs)
- 此beta版已额满_坚果 Pro 3 发布 Smartisan OS v7.5.0早期众测版
- 软件工程McCabe环路复杂度计算,自环情况详解。
- spring boot过滤器FilterRegistrationBean