上一篇文章强调了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年的码农,现在任架构师。喜欢研究技术,崇尚简单快乐。追求以通俗易懂的语言解说技术,希望所有的读者都能看懂并记住。下面是公众号和知识星球的二维码,欢迎关注!

       

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

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

    上一篇文章整体非常轻松,因为在容器启动前,只注册了一个bean定义,就是SpringBoot的主类. OK,今天接着从容器的启动入手,找出剩余所有的bean定义的注册过程. 具体细节肯定会颇为复杂,同 ...

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

    别看Spring现在玩的这么花,其实它的“筹码”就两个,“容器”和“bean定义”. 只有先把bean定义注册到容器里,后续的一切可能才有可能成为可能. 所以在进阶的路上如果要想走的顺畅些,彻底搞清楚 ...

  3. eclipse&myeclipse 生成jar包后,spring无法扫描到bean定义

    问题:eclipse&myeclipse 生成jar包后,spring无法扫描到bean定义 在使用getbean或者扫包时注入bean失败,但在IDE里是可以正常运行的? 原因:导出jar未 ...

  4. Spring 通过@Import实现Bean的注册

    今天看到一个神奇的用法, Spring可以通过@Import导入实现了ImportBeanDefinitionRegistrar接口的类来注册那个类. ImportBeanDefinitionRegi ...

  5. 品Spring:bean工厂后处理器的调用规则

    上一篇文章介绍了对@Configuration类的处理逻辑,这些逻辑都写在ConfigurationClassPostProcessor类中. 这个类不仅是一个“bean工厂后处理器”,还是一个“be ...

  6. 品Spring:详细解说bean后处理器

    一个小小的里程碑 首先感谢能看到本文的朋友,感谢你的一路陪伴. 如果每篇都认真看的话,会发现本系列以bean定义作为切入点,先是详细解说了什么是bean定义,接着又强调了bean定义为什么如此重要. ...

  7. 品Spring:真没想到,三十步才能完成一个bean实例的创建

    在容器启动快完成时,会把所有的单例bean进行实例化,也可以叫做预先实例化. 这样做的好处之一是,可以及早地发现问题,及早的抛出异常,及早地解决掉. 本文就来看下整个的实例化过程.其实还是比较繁琐的. ...

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

    其实对Spring的了解达到一定程度后,你就会发现,无论是使用Spring框架开发的应用,还是Spring框架本身的开发都是围绕着注解构建起来的. 空口无凭,那就说个最普通的例子吧. 在Spring中 ...

  9. 品Spring:对@PostConstruct和@PreDestroy注解的处理方法

    在bean的实例化过程中,也会用到一系列的相关注解. 如@PostConstruct和@PreDestroy用来标记初始化和销毁方法. 平常更多的是侧重于应用,很少会有人去了解它背后发生的事情. 今天 ...

随机推荐

  1. 力导向图(关系图) echarts的运用

    <template> <div class="demo"> <div id="grap" class="grap&quo ...

  2. Spring学习之旅(六)--SpringMVC集成

    对大多数 Java 开发来说,基于 web 的应用程序是我们主要的关注点. Spring 也提供了对于 web 的支持,基于 MVC 模式的 Spring MVC 能够帮助我们灵活和松耦合的完成 we ...

  3. Codeforces 1009E

    题意略. 思路: 比如现在n = 11.那么我们观察a[1.....n]的出现次数: a[1]:2 ^ 10 + 10 * 2 ^ 9 a[2]:2 ^ 9 + 9 * 2 ^ 8 a[3]:2 ^ ...

  4. python入门(六)二次编码与文件操作

    二次编码 密码本: ascii -- 没有中文 英文1字节 gbk -- 英文 8b(位) 1B(字节) 中文 16b 2B unicode -- 英文32b 4B 中文32b 4B utf-8 -- ...

  5. 爬虫——网页解析利器--re & xpath

    正则解析模块re re模块使用流程 方法一 r_list=re.findall('正则表达式',html,re.S) 方法二  创建正则编译对象 pattern = re.compile('正则表达式 ...

  6. Bluetooth(蓝牙)连接过程分析

    一 基本概念 蓝牙的连接过程是十分重要的,特别是做蓝牙的技术人员来说,这个是十分重要的.理它的流程,是一件必修课.虽然进入蓝牙行业很久了,以前没怎么系统化的做一些事情,趁此机会,就梳理一下这里面的内容 ...

  7. Django学习笔记(一):第一个django程序

    1.创建和运行 django-admin startproject xxx python manage.py runserver 2.第一个项目程序 wsgi.py中文名:python服务器网关接口. ...

  8. java中自定义注解的应用

    要想深刻的理解注解,我们必须能实现自己的注解,然后应用自己的注解去实现特定的业务,使用注解可以更优雅的做到某些事情. 有这样一个场景,在需要文件导出时,我们需要将一个model中的一些重要字段导出到c ...

  9. 【Offer】[52] 【两个链表的第一个公共结点】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 输入两个链表,找出它们的第一个公共结点.下图中6为公共结点:  牛客网刷题地址 思路分析 如果两个链表有公共节点,那么公共节点出现在两 ...

  10. Python操作MongoDB文档数据库

    1.Pymongo 安装 安装pymongo: pip install pymongo PyMongo是驱动程序,使python程序能够使用Mongodb数据库,使用python编写而成: 2.Pym ...