品Spring:SpringBoot轻松取胜bean定义注册的“第一阶段”

上一篇文章强调了bean定义注册占Spring应用的半壁江山。而且详细介绍了两个重量级的注册bean定义的类。

今天就以SpringBoot为例,来看看整个SpringBoot应用的bean定义是如何注册进容器的。

先来看看经典的启动入口,如下图01:

可以看到调用的是run方法,并把主类(main或primary)作为第一个参数出入。

接下来要做的事情,就是顺藤摸瓜,看看到底发生了什么,并确定下究竟哪些类被注册了bean定义。

此时,我就是一个快乐的小侦探,OK,走起。

上面的调用走到了这里,如下图02:

可以看到把第一个参数(即主类)放入数组里,又调用了一个run方法,如下图03:

使用第一个参数(即主类)去调用了构造函数,得到了实例对象,然后又调用了实例的run方法。

顺着构造函数走下去,最终走到了这里,如图04:

发现最终主类被,放到Set<Class<?>>类型的primarySources字段中。

编程新说注:通过搜索全类,发现这个字段除了刚刚放入的主类外,再没有放入其它类。

接着再沿着run方法往下走,来到了这里,如下图05:

首先定义了一个容器类的变量,然后创建容器类的实例,就是通过反射调用构造函数了。

然后就是准备容器,进入方法里看看,如下图06:

在方法最后终于看到了我们期望的,即bean定义的注册。

发现要注册的资源是getAllSources()这个方法返回的,那就进去看看吧,如下图07:

看到资源来自于primarySources字段和sources字段。第一个字段上文已经讲了,只包含主类。

编程新说注:通过搜索全类,发现第二个字段sources是null,因此它不包含资源。

因此,真正获取到的用于注册bean定义的资源只有主类自己。

那就打破砂锅走到底,继续吧。

再来看看load方法,如下图08:

使用刚刚获取到的资源创建了BeanDefinitionLoader类的实例。

这个类是SpringBoot定义的,类似于一个门面,因为它包含了所有注册bean定义的方式。

这个类就是最后一步了,因此来看看,如下图09:

首先是一个Object[]类型(之所以用Object,是因为资源类型有多种)的sources字段,用于存储刚刚获取的资源。

剩下四个都是用来注册bean定义的,其中两个上一篇已经讲过。剩余两个是处理xml和groovy的,一个已经过时,一个尚未流行。

最后再来看一眼,生成实例时调用的构造函数,如下图10:

就是对五个字段的赋值或实例化,并无特别之处。(其实是有的,先卖个关子)

接下来就是根据资源的具体类型,使用四个bean定义注册类中的一个来注册bean定义。

这一通分析下来,推导出来的结论是:

截止到目前,只有主类自己被注册了bean定义。

为了证明这一点,把日志级别改为DEBUG,如下图11:

可以看出在源码中,把资源数组进行了debug输出。

最终输出内容,如下图12:

发现确实只注册了主类自己,没有其它。和我们分析的一样,哈哈。

到现在prepareContext已经执行完毕了,接下来该执行的就是refreshContext了。

熟悉Spring容器的都知道,refresh其实就是容器的启动了。

因此最后得出一个结论,对于“常规”的SpringBoot应用:

在Spring容器启动前,只有应用的主类自己被注册了bean定义。

What,are you kidding me?

Of course not。

那其它的那些bean定义是何时及如何注册的呢?

且听下回分解。

最后来看看主类的bean定义信息,作为一个小小的彩蛋吧。

如下图13:

可以看出bean名称符合生成规则,bean定义使用了CGLIB生成了代理。

bean的一些属性,单例、非抽象、非延迟加载、未明确定义自动装配方式、作为自动装配候选bean,非主要的等等。

bean定义的实现类是AnnotatedGenericBeanDefinition,可知是通过编程方式(而非jar包扫描)注册的bean定义。

预祝,看过本文的人都有所收获。若能转发一下,则求之不得。

>>> 品Spring系列文章 <<<

品Spring:帝国的基石

品Spring:bean定义上梁山

品Spring:实现bean定义时采用的“先进生产力”

品Spring:注解终于“成功上位”

品Spring:能工巧匠们对注解的“加持”

品Spring:SpringBoot和Spring到底有没有本质的不同?

品Spring:负责bean定义注册的两个“排头兵”

作者是工作超过10年的码农,现在任架构师。喜欢研究技术,崇尚简单快乐。追求以通俗易懂的语言解说技术,希望所有的读者都能看懂并记住。下面是公众号和知识星球的二维码,欢迎关注!

       

原文地址:https://www.cnblogs.com/lixinjie/p/taste-spring-008.html

时间: 2024-08-30 09:44:49

品Spring:SpringBoot轻松取胜bean定义注册的“第一阶段”的相关文章

品Spring:SpringBoot发起bean定义注册的“二次攻坚战”

上一篇文章整体非常轻松,因为在容器启动前,只注册了一个bean定义,就是SpringBoot的主类. OK,今天接着从容器的启动入手,找出剩余所有的bean定义的注册过程. 具体细节肯定会颇为复杂,同样,大家只需关注都干了什么,不用考虑如何干的. 来宏观的看下容器的启动过程,即refresh方法,如下图01: 只捡重要的来说,就是四大步: 第一,准备好bean工厂(BeanFactory). 第二,调用已经注册的bean工厂后处理器(BeanFactoryPostProcessor). 第三,注

Spring学习笔记5 - Bean定义继承

bean定义可以包含很多的配置信息,包括构造函数的参数,属性值,容器的具体信息. 例如初始化方法,静态工厂方法名等等. 子bean的定义继承父定义的配置数据.子定义可以根据需要重写一些值,或添加其他值(与Java类的继承概念一致). 当使用基于XML的配置元数据时,通过使用父属性,指定父bean作为该属性的值来表明子bean的定义. 示例: 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmln

品Spring:注解之王@Configuration和它的一众“小弟们”

其实对Spring的了解达到一定程度后,你就会发现,无论是使用Spring框架开发的应用,还是Spring框架本身的开发都是围绕着注解构建起来的. 空口无凭,那就说个最普通的例子吧. 在Spring中要启用一项XXX功能,标准做法就是用@EnableXXX这种“启用”类型的注解. 那么这种类型的注解一般都做了什么呢?分析一下吧. 看过本号文章的人都知道,Spring的核心就是bean定义和bean,如果我想增加某方面的功能,只需写若干个类,并作为bean定义注册到容器中即可. 因此“启用”类型的

品Spring:对@Autowired和@Value注解的处理方法

在Spring中能够完成依赖注入的注解有JavaSE提供的@Resource注解,就是上一篇文章介绍的. 还有JavaEE提供的@javax.inject.Inject注解,这个用的很少,因为一般都不会去引用JavaEE的jar包. 编程新说注:JavaEE早已经被Oracle抛弃了.JavaEE这个名字已经成为历史. 还有两个就是@Value和@Autowired注解,这可是Spring自己的亲孩子.所以这两个使用的最多. 虽然注解不一样,但是目的一样,都是用来进行依赖注入,而且Spring处

品Spring:SpringBoot和Spring到底有没有本质的不同?

现在的Spring相关开发都是基于SpringBoot的. 最后在打包时可以把所有依赖的jar包都打进去,构成一个独立的可执行的jar包.如下图13: 使用java -jar命令就可以运行这个独立的jar包.如下图14: 这个jar包的执行入口就是一个main函数,典型的格式如下: @SpringBootApplicationpublic class TasteSpringApplication {    public static void main(String[] args) {     

品Spring:bean定义上梁山

认真阅读,收获满满,向智慧又迈进一步... 技术不枯燥,先来点闲聊 先说点好事高兴一下.前段时间看新闻说,我国正式的空间站建设已在进行当中.下半年,长征五号B运载火箭将在海南文昌航天发射场择机将空间站核心舱发射升空.预计用2到3年将空间站建好. 虽然到时你们不让我上去,不过我也为这件事出不了什么力,算扯平了.哈哈,但是我还是会衷心的祝福你. 长征五号火箭首次采用5米大直径的箭体结构,总加注量达到780吨,起飞时共有10台发动机产生1078吨的推力,具备近地轨道25吨.地球同步转移轨道14吨的运载

开涛spring3(12.3) - 零配置 之 12.3 注解实现Bean定义

12.3  注解实现Bean定义 12.3.1  概述 前边介绍的Bean定义全是基于XML方式定义配置元数据,且在[12.2注解实现Bean依赖注入]一节中介绍了通过注解来减少配置数量,但并没有完全消除在XML配置文件中的Bean定义,因此有没有方式完全消除XML配置Bean定义呢? Spring提供通过扫描类路径中的特殊注解类来自动注册 Bean定义.同注解驱动事务一样需要开启自动扫描并注册Bean定义支持,使用方式如下(resources/chapter12/ componentDefin

Spring IOC(2)----如何注册bean定义

前面说到IOC容器在刷新之前的一些初始化工作,现在来看看在refresh()方法中,是怎样来加载注册我们自己的bean定义的. refresh()方法中有很多功能,从注释中就可以看出来 我们本次重点关注invokeBeanFactoryPostProcessors(beanFactory);这个方法 该方法里面可以获取到前面初始化好的注解读取器AnnotatedBeanDefinitionReader,前面在AnnotationConfigUtils#registerAnnotationConf

Spring Boot 使用Java代码创建Bean并注册到Spring中

从 Spring3.0 开始,增加了一种新的途经来配置Bean Definition,这就是通过 Java Code 配置 Bean Definition. 与Xml和Annotation两种配置方式不同点在于: 前两种Xml和Annotation的配置方式为预定义方式,即开发人员通过 XML 文件或者 Annotation 预定义配置 bean 的各种属性后,启动 Spring 容器,Spring 容器会首先解析这些配置属性,生成对应都?Bean Definition,装入到 DefaultL