首页 技术 正文
技术 2022年11月10日
0 收藏 335 点赞 4,700 浏览 1697 个字

人见人爱的 Spring 已然不仅仅只是一个框架了。如今,Spring 已然成为了一个生态。但深入了解 Spring 的却寥寥无几。这里,我带大家一起来看看,我是如何手写 Spring 的。我将结合对 Spring 十多年的研究经验,用不到 400 行代码来描述 Spring IOC、DI、MVC 的精华设计思想,并保证基本功能完整。

首先,我们先来介绍一下 Spring 的三个阶段,配置阶段、初始化阶段和运行阶段(如图):

我是这样手写 Spring 的(麻雀虽小五脏俱全)

配置阶段:主要是完成 application.xml 配置和 Annotation 配置。

初始化阶段:主要是加载并解析配置信息,然后,初始化 IOC 容器,完成容器的 DI 操作,已经完成 HandlerMapping 的初始化。

运行阶段:主要是完成 Spring 容器启动以后,完成用户请求的内部调度,并返回响应结果。

先来看看我们的项目结构 (如下图)

我是这样手写 Spring 的(麻雀虽小五脏俱全)

一、配置阶段

我采用的是 maven 管理项目。先来看 pom.xml 文件中的配置,我只引用了 servlet-api 的依赖。

我是这样手写 Spring 的(麻雀虽小五脏俱全)

然后,创建 GPDispatcherServlet 类并继承 HttpServlet,重写 init()、doGet() 和 doPost() 方法。

我是这样手写 Spring 的(麻雀虽小五脏俱全)

在 web.xml 文件中配置以下信息:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

在中,我们配置了一个初始化加载的 Spring 主配置文件路径,在原生框架中,我们应该配置的是 classpath:application.xml。在这里,我们为了简化操作,用 properties 文件代替 xml 文件。以下是 properties 文件中的内容:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

接下来,我们要配置注解。现在,我们不使用 Spring 的一针一线,所有注解全部自己手写。

创建 GPController 注解:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

创建 GPRequestMapping 注解:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

创建 GPService 注解:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

创建 GPAutowired 注解:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

创建 GPRequestParam 注释:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

使用自定义注解进行配置:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

到此,我们把配置阶段的代码全部手写完成。

二、初始化阶段

先在 GPDispatcherServlet 中声明几个成员变量:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

当 Servlet 容器启动时,会调用 GPDispatcherServlet 的 init()方法,从 init 方法的参数中,我们可以拿到主配置文件的路径,从能够读取到配置文件中的信息。前面我们已经介绍了 Spring 的三个阶段,现在来完成初始化阶段的代码。在 init() 方法中,定义好执行步骤,如下:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

doLoadConfig() 方法的实现,将文件读取到 Properties 对象中:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

doScanner() 方法,递归扫描出所有的 Class 文件

我是这样手写 Spring 的(麻雀虽小五脏俱全)

doInstance() 方法,初始化所有相关的类,并放入到 IOC 容器之中。IOC 容器的 key 默认是类名首字母小写,如果是自己设置类名,则优先使用自定义的。因此,要先写一个针对类名首字母处理的工具方法。

我是这样手写 Spring 的(麻雀虽小五脏俱全)

然后,再处理相关的类。

我是这样手写 Spring 的(麻雀虽小五脏俱全)

doAutowired() 方法,将初始化到 IOC 容器中的类,需要赋值的字段进行赋值

我是这样手写 Spring 的(麻雀虽小五脏俱全)

initHandlerMapping() 方法,将 GPRequestMapping 中配置的信息和 Method 进行关联,并保存这些关系。

我是这样手写 Spring 的(麻雀虽小五脏俱全)

到此,初始化阶段的所有代码全部写完。

三、运行阶段

来到运行阶段,当用户发送请求被 Servlet 接受时,都会统一调用 doPost 方法,我先在 doPost 方法中再调用 doDispach() 方法,代码如下:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

doDispatch() 方法是这样写的:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

到此,我们完成了一个 mini 版本的 Spring,麻雀虽小,五脏俱全。我们把服务发布到 web 容器中,然后,在浏览器输入:http://localhost:8080/demo/query.json?name=Tom,就会得到下面的结果:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

当然,真正的 Spring 要复杂很多,但核心设计思路基本如此。例如:Spring 中真正的 HandlerMapping 是这样的:

我是这样手写 Spring 的(麻雀虽小五脏俱全)

我在网络上也有现场直播手写 Spring,欢迎大家关注。如果在练习过程中有任何疑问,可以加我的架构群:586446657。

欢迎工作一到五年的 Java 的工程师朋友们加入进来,

本群提供免费的学习指导架构资料以及免费的解答

不懂得问题都可以在本群提出来之后还会有职业生涯规划以及面试指导

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,489
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,904
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,737
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,490
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,128
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,291