手写Spring MVC

2019-09-24 00:00:00 spring 手写 MVC

闲及无聊 又打开了CSDN开始看一看有什么先进的可以学习的相关帖子,这时看到了一位大神写的简历装X必备,手写Spring MVC。

我想这个东西还是有一点意思的 就拜读了一下大佬的博客 通读了一遍相关代码 感觉和我想象中spring的运作流程基本相同  但是我脑海中基本上只有一个非常简单的基本概念 而这位大佬具象化了相关的代码内容 值得学习一番。

同样的我的博客里代码都是图片 需要膜拜学习原博的同志 可以参考

版权声明:本文为CSDN博主「肖朋伟」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40147863/article/details/96505433(代码可复制)

学习自《Spring 5核心原理与30个类手写实战》作者 Tom 老师

全文核心!!!!!!看明白了 才能真的学会如何去写 本文代码基本照搬肖老师的代码 在其中增加了一些自己学习的理解和心得

一、整体思路
思路要熟练背下来

1)配置阶段

配置 web.xml:
<sevlet>
XDispatchServlet          //继承HttpServlet类 重写doGet doPost init三个函数 在web.xml中配置的原因为保证在tomcat启动的时候对此类进行初始化 保证初始化的完成

设定 init-param: contextConfigLocation = applicationContext.properties          // 在类加载时 将配置文件初始化到 servlet的配置对象中 方便获取其中启动参数
<servlet-mapping>
设定 url-pattern: /*     // 表示此servlet接受并处理一切借口
配置 Annotation: @XController @XService @XAutowired @XRequestMapping      // 自定义注解类 从代码实现上来看 是类别的表示 方便Spring在通过反射方式加载相关对象时 能够更准确的对需要加载的对象进行分类 而不需要每个类进行逐条审查
2)初始化阶段

IOC:
调用 init() 方法: 加载配置文件
IOC 容器初始化: Map<String, Object>
扫描相关的类: scan-package=“com.xiaopengwei”
创建实例化并保存到容器: 同过反射机制将类实例化放入 IOC 容器中

 

PS:ioc容器 控制反转 主要作用为在tomcat启动时 将配置扫描路径下的相关对象全部初始化到一个map对象中 在需要使用时可以将相关对象直接进行使用 不会说 到了使用的时候在对相关对象进行加载 且不会出现重复某一对象重复生成多个实例的场景

从某种程度上缓解了内存的压力 ioc容器 核心就是一个Map对象存储需要使用的bean对象 通过beanId或beanName来对应 在需要使用的地方进行调用 且ioc容器就是java设计模式中工厂模式的经典使用。

DI:
进行 DI 操作: 扫描 IOC 容器中的实例,给没有赋值的属性自动赋值

 

PS:DI 注入 Spring容器中提供 参数注入 构造器注入 自动注入等方式 而本文中展示的为注解类型的自动注入 但是从本质上来说集中注入方式都是一样的 即可以理解为 在程序启动时加载某种注入的规则 即通过反射的方式将什么对象 注入至另一个的对象中的某个值中

MVC:
初始化 HandlerMapping: 将一个 URL 和一个 Method 进行一对一的关联映射 Map<String, Method>

 

PS:本文中的MVC相关基本只是url及对应函数之间的一个映射关系 参数及post请求中json字符串转化为相应对象的功能并未实现  但其实参数绑定 其实就是简单的参数名映射 json与类对象之间的相互转换 只要熟悉json对象的构造方式及简单的反射方法即可实现 何况 相关json对象解析的相关插件也有很多 如果有时间可以看一次相关插件的源码 了解一下人家关于类对象及反射的理解 从中学习

3)运行阶段

调用 doGet() / doPost() 方法: Web 容器调用 doGet() / doPost() 方法,获得 request/response 对象
匹配 HandleMapping: 从 request 对象中获得用户输入的 url,找到其对应的 Method
反射调用 method.invoker(): 利用反射调用方法并返回结果
response.getWrite().write(): 将返回结果输出到浏览器

 

PS:web容器已经相当于设定了相对稳定的规则 重写了其中的doGet/doPost方法即在http相关处理过程中加入了自己想要的一些处理 及自己的解析规则(Restful风格接口 从某种程度上来说 就复杂于本文中 的解析规则)

PS::突然想到了一句题外话 正因为重写了doGet及doPost方法 才给了aop处理的空间  假设 我们在初始化时 解析配置文件 增加一个Map<Object(aop执行规则,在什么函数之前 或在什么函数之后执行), method(需要执行的方法)> 然后在get及post方法实际处理方法的前后加上一个 针对此map的判断 不就实现了aop面向切面的思想了吗!!!

 

二、代码

1、代码架构

《手写Spring MVC》

 

 简单的区分了spring容器需要的简化的一些对象

 

2、pom.xml 

《手写Spring MVC》

 

 junit为默认加载的 实际上 spring还是基于servlet相关处理的一个机制 只是在此机制上 大大的发展和简化了很多地方的代码开发及冗余

使我们java从业人员可以更好的 更简易的进行相关代码开发工作

 

3、web.xml

《手写Spring MVC》

 

 手写Spring的核心 XDispatchServlet 在此类中完成相关对象的初始化及注入工作

 

4、application.propertis

《手写Spring MVC》

 

 

见名知意 扫描路径 设计思路及扫描此路径像的相关对象 并初始化加载至ioc容器中

 

5、自定义注解类

《手写Spring MVC》

 

自动注入注解

《手写Spring MVC》

 

 controller注解

《手写Spring MVC》

 

 url相应路径注解

《手写Spring MVC》

 

 Service类注解

 

PS:本来想在此详细解析@Target@Retention@Documented@interface等元注解 但是在搜索学习是被一篇博客教育的服服帖帖 建议大家可以学习一下

https://www.cnblogs.com/gmq-sh/p/4798194.html

如果不愿去看的话在此简要说明一下

@Target主要为标记当前注解使用的地点 TYPE为类、METHOD为方法、FILED为参数

@Retention主要表示此注解标识的对象生命周期 RUNTIME标识运行时使用 基本就会一直加载在运行内存中

@Documented Documented注解表明这个注释是由 javadoc记录的,在默认情况下也有类似的记录工具。 如果一个类型声明被注释了文档化,它的注释成为公共API的一部分(这个说明感觉比网址中的说明好理解一下 但是说实话 还是不太清楚这个的意义 还有待学习 希望日后学到其他的知识时可以理解)

 

6、核心XDispatchServlet

《手写Spring MVC》

 

 相关引用

《手写Spring MVC》

 

 初始化常量

《手写Spring MVC》

 

 重启doGet及doPost方法

《手写Spring MVC》

 

 自定义请求处理器(理论上就可以在这个函数中增加aop相关操作)

《手写Spring MVC》

 

 重写servlet初始化方法 保证在tomcat启动时相关对象的加载

 

《手写Spring MVC》

 

 初始化相关对象打印

《手写Spring MVC》

 

 url请求映射对象初始化

《手写Spring MVC》

 

 自动化注入

《手写Spring MVC》

《手写Spring MVC》

 

ioc容器初始化

《手写Spring MVC》

 

 扫描路径下的相关类对象 因牵扯到文件夹的搜索 所以采用递归方式层层搜索加载

《手写Spring MVC》

 

 记载配置

《手写Spring MVC》

 

 此处字母大小写变更方式很有意思 牵扯到char值存储的一个因素 char值存储任何中文或英文其实内部存储的可以理解为一个标识码,此处已经默认className的首字母必然为大写所以未经判断 这个在实际应用中应该避免 

如果对char值存储的字符码值有兴趣可以百度搜索Unicode字符列表 至于为什么是加32 因为unicode字符集采用的计算方式为16进制 具体对应码可以百度查询

 

PS:因代码编写习惯 所以其实图片应该从下向上看 其实更符合此类加载的一个顺序 但更建议敲出来 直接在init方法中点进去关联着看

7、controller类

《手写Spring MVC》

 

《手写Spring MVC》

 

此处主要是为了展现自动注入及url映射的一个处理

 

8、服务层接口类

《手写Spring MVC》

 

 实现类

《手写Spring MVC》

 

 

 此处模拟实现假设是真的返回了业务处理后应返回的相关返回

 

 三、代码运行

《手写Spring MVC》

 

 《手写Spring MVC》

 

 这个SpringMocker是我的项目名称如果不做特殊处理的话需要在url中增加此字段,即doDispatch函数中解析忽略的contextPath字段

 

如果需要隐藏项目名称需要在tomcat的conf目录下找到server.xml配置文件的HOST标签

<Context path=”” docBase=”SpringMocker” />在其中增加如此字段即可

《手写Spring MVC》

 

 效果如下

 

《手写Spring MVC》

 

相关文章