Spring 4.0手写 之Spring MVC
预习

课程目标
高仿真手写Spring MVC**:不是使用Spring,而是自己动手写一个简化版本的Spring MVC框架。
-
搭建基本框架:能够实现核心功能,包括请求分发、业务处理、视图解析等。
-
理解设计模式:通过自己实现框架,感受Spring底层的设计思
内容定位
-
前提:完全掌握Spring系统结构和设计模式。
-
目的:通过实践加深对Spring MVC架构的理解,理解作者创作意图。
课程大纲重点
第一章:MVC顶层设计
GPDispatcherServlet请求调度
-
类似Spring中的DispatcherServlet
-
核心功能:接收请求 → 找到对应的Handler → 调用HandlerAdapter → 返回ModelAndView
-
作用:所有请求都先经过它,就像商场前台接待,收到客户需求后决定交给谁处理。
流程:收到请求 → 找到对应“业务处理人(Handler)” → 调用“助手(HandlerAdapter)” → 收集结果 → 返回给客户。
GPHandlerMapping请求映射
-
URL与Controller方法映射
-
实现方式类似Spring的@RequestMapping
-
作用:知道每个请求该找哪个处理器,就像公司内部地图标明“客户A找销售部,客户B找客服部”。
实现:URL ↔ Controller方法的对应关系。类似Spring中的
@RequestMapping("/xxx")。
GPHandlerAdapter请求方法适配器
-
统一调用不同Controller方法,解耦请求与方法调用
-
支持方法参数自动注入
-
作用:不管不同的Controller方法参数长啥样,它都能正确调用。
类似:不同部门的员工用不同语言/格式写报告,助手统一转换成可处理的形式再执行。
特性:支持自动注入方法参数(如请求参数、对象)。
GPModelAndView页面数据封装
-
作用:把Controller处理结果和视图信息一起打包,就像快递包装:里面有商品(数据)和收件人信息(视图)。
Controller返回这个包装,DispatcherServlet拿到后交给视图解析器。
-
封装返回的数据和视图名称
GPViewResolver视图解析器
-
将逻辑视图名解析为实际物理页面
-
作用:把逻辑视图名(如“home”)翻译成实际页面路径(如
/WEB-INF/views/home.html)。这样Controller不用管具体物理路径,只返回逻辑名字。
GPView自定义模板引擎
-
简单实现数据填充、动态展示模板
-
作用:把数据填充到模板中,生成最终页面。
类似:菜单(模板) + 食材(数据) → 做出成品菜(网页)。
用户请求 → 总指挥(DispatcherServlet) → 查地图找人(HandlerMapping) → 万能助手调用方法(HandlerAdapter) → 处理结果打包(ModelAndView) → 找到具体地址(ViewResolver) → 厨师做出成品(View模板引擎) → 用户看到网页。
第二章:业务代码实现
IQueryService / QueryService:查询逻辑接口与实现
IModifyService / ModifyService:增删改逻辑接口与实现
MyAction / PageAction:控制器处理逻辑,调用业务层并返回ModelAndView
第三章:定制模板页面
-
first.html:动态数据展示
-
404.html:请求页面未找到
-
500.html:服务器异常页面
第四章:运行效果演示
-
演示整个手写MVC框架的功能:请求分发、业务处理、视图返回
理解Spring MVC实现原理:
-
请求生命周期:客户端 → DispatcherServlet → HandlerMapping → HandlerAdapter → Controller → ModelAndView → ViewResolver → 客户端
-
设计模式:单例、工厂、策略、模板方法等
完成MVC手写实现:
-
GPDispatcherServlet核心调度
-
GPHandlerMapping、GPHandlerAdapter的请求处理
-
ModelAndView和ViewResolver的逻辑
设计
gitee
v1是mvc版本的内容
主分支就是spring容器的功能


逻辑
根据URl拿到Handler
根据handler拿到handleradapter
根据adapter拿到对应的modelandView
根据ViewResolver找到view对象
view对象渲染页面返回
完成大致框架
https://gitee.com/laomaodu/as/commit/f243a7dbe6bc8d9c67610692de156636773f358f
接下来就是具体的委派了
processDispatchResult
viewResolver //视图解析器
return new GPView(templateFile);
GPView
GPView 的职责是视图渲染(View Rendering),而不是视图定位或选择。GPViewResolver 已完成“找到哪个视图文件”,GPView 只负责“如何把模型数据渲染成 HTTP 响应”。
GPModelAndView
Adapter
DispatcherServlet → HandlerMapping → HandlerAdapter → Controller 方法
HandlerMapping 决定 *调用谁*,HandlerAdapter 决定 *怎么调用*。
GPHandlerAdapter 的作用: 将 HTTP 请求参数与 Controller 方法参数进行匹配、类型转换与注入,并通过反射执行目标方法,返回统一的 ModelAndView。
聊聊总流程
init
//初始化Spring核心IoC容器
applicationContext = new GPApplicationContext(config.getInitParameter("contextConfigLocation"));
省略
initStrategies
只聊视图
initStrategies(applicationContext);
initHandlerMappings(applicationContext);
职责
URL 绑定关系 //映射关系
handlerMappings 存储关系
handlerMappings.add(new GPHandlerMapping(pattern,instance,method));
public class GPHandlerMapping {
private Pattern pattern; //URL
private Method method; //对应的Method
private Object controller;//Method对应的实例对象
}
//初始化参数适配器
initHandlerAdapters(applicationContext);
private void initHandlerAdapters(GPApplicationContext applicationContext) {
//一个mapping对应一个 Adapters 控制台处理
for (GPHandlerMapping handlerMapping : handlerMappings) {
this.handlerAdapters.put(handlerMapping,new GPHandlerAdapter());
}
}
initHandlerAdapters 负责 happing对应adapters绑定 为了
adapter参数拼凑和 方法执行
private Map<GPHandlerMapping,GPHandlerAdapter> handlerAdapters = new HashMap<GPHandlerMapping, GPHandlerAdapter>();
GPHandlerAdapter 负责
initViewResolvers(applicationContext);
//初始化视图转换器
//视图 private List<GPViewResolver> viewResolvers = new ArrayList<GPViewResolver>();

doDispatch
//1、通过URL获得一个HandlerMapping
GPHandlerMapping handler = getHandler(req);
if(handler == null) {
processDispatchResult(req, resp, new GPModelAndView("404"));
return;
}
//2、根据一个HandlerMaping获得一个HandlerAdapter
GPHandlerAdapter ha = getHandlerAdapter(handler);
//3、解析某一个方法的形参和返回值之后,统一封装为ModelAndView对象
GPModelAndView mv = null;
if (ha != null) {
mv = ha.handler(req,resp,handler);//反射执行invoke 还涉及到参数的计算
}
// 4就把ModelAndView变成一个ViewResolver
processDispatchResult(req,resp,mv);
private void processDispatchResult(HttpServletRequest req, HttpServletResponse resp, GPModelAndView mv) throws IOException {
if(null == mv){return;}
if(this.viewResolvers.isEmpty()){return;}
for (GPViewResolver viewResolver : this.viewResolvers) {
GPView view = viewResolver.resolveViewName(mv.getViewName());//GPView
//直接往浏览器输出
view.render(mv.getModel(),req,resp);
return;
}
}
GPView
Controller ↓ 返回 GPModelAndView DispatcherServlet ↓ GPViewResolver(找到模板文件) ↓ GPView.render(本类) ↓ HttpServletResponse 输出 HTML
GPView 的作用: 读取 HTML 模板,解析占位符,从 Model 中取值并替换,最终生成响应内容返回给浏览器。
resp.setCharacterEncoding("utf-8");
resp.getWriter().write(sb.toString());
更多推荐



所有评论(0)