手撕spring核心源码,彻底搞懂spring流程

引子

十几年前,刚工作不久的程序员还能过着很轻松的日子。记得那时候公司里有些开发和测试的女孩子,经常有问题解决不了的,不管什么领域的问题找到我,我都能帮她们解决。但是那时候我没有主动学习技术的意识,只是满足于解决问题,错过了能力提升最好的阶段。

老公是个截然相反的类型,我就看他天天在宿舍里学习。学来学去也就那样了。他不陪我玩,我虽然心里不乐意,但是还好那时候未卜先知:知道自己能生一个长的帅、和我兴趣相投、天天粘我,我在他旁边他睡觉都能笑出声的儿子,就忍下了。我就自己学学历史、文学,出去上个外语培训班,什么感兴趣学什么。就是正经工作中的东西不学。

后来才发现自己犯了多大一个错误:没有尽早建立一个系统性的知识体系和思维,还影响了思维上的连续性和逻辑性。武侠故事里一夜得到神功是骗人的,功夫还在平时。老公看似做了十几年长进不大的事,基础却非常扎实,有功力。但是如果他能头脑再活络些,掌握要领,可以事半功倍。

很多朋友想学习Spring,总是很快地从入门到放弃。原因是头脑中没有框架,学到的东西没有索引,最终被深藏于记忆深处。本文通过手撕spring核心源码的方式,旨在让大家可以在头脑中形成一个spring框架,然后自己在工作中可以带着问题翻看源码,给这个框架添枝加叶,最终形成了一个饱满的spring知识体系。

本文整体采用由浅入深的逻辑结构。侧重于面向于平时工作或学习中用spring写过业务代码的朋友。

HelloWorld版本Spring启动代码

有些朋友可能写过或者见过ClassPathXmlApplicationContext、AnnotationConfigApplicationContext,它们都是常见的spring容器或者是上下文。既然说到这里,就先来解释什么是spring容器,什么是spring上下文。

Spring的核心就是容器,负责对象的整个生命周期:创建、管理、销毁程序执行过程中需要的对象。

Spring容器又分为两种类型:第一种是BeanFactory,最简单的容器,只能提供基本的DI功能)另一种是:继承了BeanFactory后派生而来的ApplicationContext,被称之为Spring上下文。能提供更多企业级的服务。咱们最常用的还是基于IOC(控制反转)的上下文容器。

现在SpringBoot使用的很多,所以今天咱们手撕的主要是实现 AnnotationConfigApplicationContext 这个注解上下文的原理。

咱们开始手撕。参照下面咱们用 spring 的方法,首先要有一个上下文将配置参数传入,然后有一个 getBean 可以获取对象来使用。

手撕spring核心源码,彻底搞懂spring流程

那咱们就根据这两个特质自己写一个类,要点如下图1和2两步。

手撕spring核心源码,彻底搞懂spring流程

既然需要将configClass配置类作为参数传入,就先来构造一个空的配置类。

手撕spring核心源码,彻底搞懂spring流程

这样从表面上,就可以像使用AnnotationConfigApplicationContext一样使用Spring容器了。

手撕spring核心源码,彻底搞懂spring流程

为了标注重点和屏蔽用户终端差异带来的文章阅读体验差异,这里我直接用的截图。代码文字在 https://github.com/xiexiaojing/yuna 里可以找到。

手撕Spring扫描流程

所谓HelloWorld版本就是除了入门,其他没有任何作用。咱们希望它可以实现自动扫描文件夹下的带有@Component注解的Bean完成注入。首先自己来新建一个@Component注解:

手撕spring核心源码,彻底搞懂spring流程

并在UserService中使用这个注解:

手撕spring核心源码,彻底搞懂spring流程

当然,Component注解是用来扫描的,那还得来定义一个扫描注解,就是把Component注解复制一份,改个名字:

手撕spring核心源码,彻底搞懂spring流程

ComponentScan这个注解要加在YunaConfig上,通过它来加载扫描配置:

手撕spring核心源码,彻底搞懂spring流程

咱们再回到YunaApplicationContext,配置类定义完之后,咱们下一步上下文就来解析它:

手撕spring核心源码,彻底搞懂spring流程

这时候咱们回到main方法,运行结果:

手撕spring核心源码,彻底搞懂spring流程

咱们拿到了解析路径,但是UserService这个Bean还是空的。重点来了,下面的代码要注意看:

手撕spring核心源码,彻底搞懂spring流程

上面首先使用hutool工具扫描path得到包下类的集合,然后从集合中过滤留下使用了Component注解的class。是不是还挺简单的?

当然,这里类还没有被实例化,所以这里只是打印一下类名看看效果:

手撕spring核心源码,彻底搞懂spring流程

从结果可以看到类已经获取到了。下一步实例化。

手撕Spring实例化对象流程

实例化对象,主要有两种作用域。一种是单例的,一种是多例的。这又要给用户选择了。给用户选择的地方都是通过注解。再将Component注解类复制一份,改名叫Scope。value默认是singleon,单例。

手撕spring核心源码,彻底搞懂spring流程

实例化对象需要一个容器来存放,首先要定义一个对象BeanDefination来存放对象的描述:

手撕spring核心源码,彻底搞懂spring流程

每个class对应一个BeanDefination,存放到一个map容器中:

手撕spring核心源码,彻底搞懂spring流程

要获取实例的时候需要判断是否是单例的,单例的就用一个map存起来下次获取时直接用,不是单例就直接实例化。

手撕spring核心源码,彻底搞懂spring流程

运行看看效果:

手撕spring核心源码,彻底搞懂spring流程

这次不是null,而是具体的实例了。但是咱们不满足于用getBean获取呀,下面咱们来看怎么自动注入。

手撕Spring依赖注入流程

首先来定义一个标识注入的注解Autowired:

手撕spring核心源码,彻底搞懂spring流程

再任意定义一个Bean做注入测试:

手撕spring核心源码,彻底搞懂spring流程

注入到UserService对象中:

手撕spring核心源码,彻底搞懂spring流程

把newInstance实例化的地方单独提取一个方法,实例化时获取类是否有Autowired注解的,有的化先实例化它:

手撕spring核心源码,彻底搞懂spring流程

测试效果:

手撕spring核心源码,彻底搞懂spring流程

总结

这里面的代码咱们在平时业务开发中常用,我也没多解释。大家有没有感觉整个流程就像做业务开发一样顺畅。其实写底层容器就是这样,原理了解了一点都不难。

大家说完这篇之后建议读读其他spring的文章,试试是不是有了深层的理解?

Spring Boot 使用的经典错误-找不到Bean了;

Spring Kafka的异步BUG

Java&Spring过时的经典语录

编程一生

因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下”在看”,加个”星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。

PDCA方法论,检查自己是否错过更新:每周三晚上8点左右,我都会更新文章,如果你没有收到,记得点开【编程一生】公众号找一下(^▽^)。如果没有找到,那可能是像本周一样,我记错了日子(꒦_꒦)

Original: https://www.cnblogs.com/xiexj/p/16099092.html
Author: 编程一生
Title: 手撕spring核心源码,彻底搞懂spring流程

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/610752/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • vue组件传值和路由——day04

    <script><br> var vm = new Vue({<br> el: ‘#app’,<br> data: {<br&…

    Linux 2023年6月7日
    094
  • PHP获取前一天,前一个月,前半年,前一年的时间戳

    // 获取前一秒 strtotime("-1 seconds"); // 获取前一分钟 strtotime("-1 minute"); //…

    Linux 2023年6月13日
    0169
  • Spring5 学习笔记

    学习地址: B站-动力节点 个人代码: GitHub Spring 概述 1.1 Spring 简介 Spring Framework 是一个使用Java开发的、轻量级的、开源框架…

    Linux 2023年6月14日
    092
  • OpenStack glance对接swift

    配置 切换环境变量 [root@controller ~]# source keystonerc_admin 复制glance配置文件备份 [root@controller ~(k…

    Linux 2023年6月8日
    089
  • 【Docker搭建】3. 在Docker中搭建Zookeeper集群

    docker pull zookeeper docker run –name zk1 -d zookeeper apt-get update apt-get install vi…

    Linux 2023年6月13日
    094
  • 在Linux下的文件IO操作

    系统调用 为什么用户程序不能直接访问系统内核提供的服务,为了更好地保护内核空间,程序的运行空间被划分为内核空间和用户空间(俗称内核状态和用户模式),它们在不同的级别上逻辑上是相互隔…

    Linux 2023年5月27日
    088
  • 【填空题】考研数据结构填空题整理

    数据结构填空题 题源来自《算法与数据结构考研试题精析》、《王道数据结构》在Liang’s Blog所著的文章上补充考点,仅供参考学习 一、概论 数据元素 是数据的基本单…

    Linux 2023年6月13日
    0114
  • POJ1322Chocolate–概论DP

    每次从包装中取出一块巧克力并放在桌子上。如果桌子上有两个相同颜色的巧克力,则将这两个丢掉。如果包中有C种颜色的巧克力(颜色均匀分布),从包装中取出N个巧克力后,桌子上确实有M个巧克…

    Linux 2023年6月7日
    0116
  • 不自由的自由职业

    大家好。我叫梁旭,以前是农民,现在是自由职业者。 [En] Hello, everyone. I’m Liangxu, a former farmer, and now…

    Linux 2023年5月27日
    0123
  • 安装win10和ubuntu双系统

    2019-06-22 ​ 最近找了一份新的工作,要用到linux,由于之前基本上没有接触过这方面的东西,所以今天捣鼓一下,安装win10和linux双系统,办公研发双不误。如果在安…

    Linux 2023年6月14日
    0106
  • Linux下如何部署FTP服务器

    FTP 是 File Transfer Protocol 的缩写,即文件传输协议,它通过网络在服务器和客户端之间传输文件,现在已经成为一种广泛使用的标准工具 vsftpd 是 ve…

    Linux 2023年6月13日
    088
  • 【CentOS】检查系统是否安装OpenSSH

    CentOS7 远程联机 哔哩哔哩 萌狼蓝天 博客:https://mllt.cc 微信公众号:萌狼蓝天 检查与安装配置OpenSSH [CentOS7]检查系统是否安装OpenS…

    Linux 2023年5月27日
    098
  • Docker镜像安全的一些(初级)检测方法

    一些使用过的工具记录。 docker scan工具 这个是docker官方工具,参考文档:https://docs.docker.com/engine/scan/ 使用方法: 命令…

    Linux 2023年6月6日
    087
  • python入门基础知识五(for循环、公共操作与推导式)

    for循环 break终止循环 a = ‘abcd’ for i in a: … if i == ‘c’: … print("’c’ stands for ‘ce…

    Linux 2023年6月7日
    0123
  • win11下关于安装umi成功后CMD命令不能使用的问题

    先找到你安装的umi全局路径 yarn global bin 然后把这个路径添加到系统变量中去:PATH 还是不能用的话就是找到 umi.cmd 文件的目录,把里面的C盘符号前面的…

    Linux 2023年6月14日
    0111
  • 最小生成树-Prim算法

    最小生成树minimal-spanning-tree(概念就不具体介绍了)有两种基于不同贪心选择的算法,一个为Prim算法,一个为Kruskal算法。 Prim和Dijkstra算…

    Linux 2023年6月7日
    094
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球