手写SpringMVC框架
一、SpringMVC的运行流程
-
用户发送请求至前端控制器DispatcherServlet
-
DispatcherServlet收到请求调用HandlerMapping处理器映射器。
-
处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
-
DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
-
执行处理器(Controller,也叫后端控制器)。
-
Controller执行完成返回ModelAndView
-
HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
-
DispatcherServlet将ModelAndView传给ViewReslover视图解析器
-
ViewReslover解析后返回具体View
-
DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
-
DispatcherServlet响应用户。
二、手写SpringMVC效果展示
-
在web.xml中指定我自定义的前端控制器 MyDispatcherServlet
-
Controller
其中:
@BXCController指定该类为Controller
@BXCRequestMapping 指定url的前缀
@BXCGetMapping Get请求
@BXCPostMapping Post请求
@BXCResponseBody 指定返回Json格式,不指定返回jsp页面
3. 测试
浏览器测试:
http://localhost:8080/MyMVC/action/Test1
http://localhost:8080/MyMVC/action/Test2
http://localhost:8080/MyMVC/action/Test3
因为这是用的@BXCPostMapping ,所以只能使用Post请求,使用PostMan返回结果:
http://localhost:8080/MyMVC/action/Test4?username=aaa&passwd=aaa
不传参数的话默认为空:
三、主要思想流程
1. 定义容器
自定义三个ConcurrentHashMap 作为容器,别存放Get的请求地址-方法Method、Post的请求地址-方法Method、及请求地址-Controller对象。
2. 使用反射获取包下所有带有@BXCController的类
使用反射获取到包下所有的Class<?>地址,依据是否含有@BXCController,有的话存到一个容器中,给下面使用。
3. 实现HandlerMapping映射地址和方法,存入容器中
遍历上面返回的容器,判断方法上是否有@BXCRequestMapping注解,有的话将value追加到url地址,再判断方法上是否含有@BXCGetMapping或者@BXCPostMapping,有就将value追加到地址,并将地址作为key,方法实体作为value放入post和get容器中,形成映射关系。
4. 过滤客户端请求
service方法,判断url是否符合要求,不符合直接返回错误,不再执行doGet、doPost。
5. 映射方法,返回不同视图
在doGet、doPost方法中拿到url地址,去对应容器中寻找,没有的话直接返回错误。然后根据地址拿到对应方法体和对象,先用反射获取对象中有哪些参数,和该对象是否含有@BXCResponseBody注解,当然这样的话每请求一次就要做一次反射和判读是否有注解,所以这两步也可以在开始初始化的时候就取出来存到容器中,可以提升一部分效率。然后根据反射出的参数名从Request中取参数,并在invoke对象中传递参数,并获取到方法返回的内容,并根据是否含有@BXCResponseBody注解返回不同形式的内容。
整体还是需要反射和Ioc思想的,如果不了解可以看下我的博客 “使用Java反射,手写SpringIOC 框架” 这篇文档。
https://blog.csdn.net/qq_43692950/article/details/107897959
虽然整体说起来看似不多,真正写起了还是要注意挺多东西的,可以自己尝试写一下,虽然这个流程和SpringMVC还是有些出入的,但实施写一遍还是可以更好的理解SpringMVC的原理。