一、MVC架构
二、springMVC全流程
三、流程简单描述
@Controller 控制器【控制器指根据req处理返回res的程序】
@RequestMapping 映射器【请求路径:控制器】 【HandlerMapper机制】 返回【HandlerExecutionChain=handler+handlerInterceptors】处理器责任链
handler 处理器【控制器后的实际处理,是对控制器的包装】
interceptors 拦截器【增强处理器功能】
handlerAdapter 适配器【得到处理器后不能直接运行,运行需要适配器】【运行HandlerExecutionChain】
【执行控制器返回JSON,轮询匹配Converter】【匹配则设置视图null】
ModelAndView 数据模型【模型Model+视图View】【data/user】
ViewResolver 视图解析器
四、阐述
springMVC和boot可以说是烂大街的普及度了。自己也用了好写年,阐述一下自己的看法,希望可以帮助大家更好的理解。
1、这里面springMVC的流程和组件是核心。很重要的就是DispatcherServlet,可是说是个开头。
2、因为springMVC和boot都是配置模式,往往是不清不楚就是开始,甚至不清不楚就完成了,所以很多写代码的老江湖其实未必知道详细的流程细节,会用却不那么懂,是很多程序员的通病。甚至一些老程序员直言,上手快就行。
我只能说,当一个老外包这样是可以的,但哄着自己玩有什么意思。热爱代码的人是不会这么看待这个问题的。
说到这里,不禁有一个灵魂问题,热爱代码有什么用?
好吧,负责任的说,并无卵用。就和你玩俄罗斯方块多过几关一样。
扯淡了,继续。
3、在springBoot机制启动后,DispactherSrvlet、HandlerAdapter等对象组件就会被初始化。其实你都不用管这些,总之记住这个springMVC相关的Bean就会存放好在spring的Bean工厂中,供应用调用。
这些组件,基本上就是:处理器、适配器、控制器、数据模型、解析器等等。
4、数据模型其实是大家最熟悉的,因为这玩意只能自己写,用到的多,所以了解。其他组件其实也和这个差不多,不难,但是用的少,我是说人家组件就在那里,你直接用是用,这不和没正经用一样吗?
5、所谓的学习springMVC,其实就是对这些组件的掌握程度了。当然,大神另算,大略就是指像我这样多少年后又无聊摸起代码的N流程序员吧。
6、映射选择器,处理器
springMVC的处理器到底是个啥?说实话,其实是两个东西,一个是映射选择器。
这个东西其实用大白话说,就是我们客户端请求的url,服务端收到这个请求以后,给穿了一件马甲,url+马甲=映射选择器。
换成类就是HandlerMapping。
这个东西很重要,就拿三国来说,前三国吕布,后三国赵云。这玩意就是个吕布。整个springMVC的前半程都是为绕它展开的。
url包装成为了HandlerMapping。
package org.springframework.web.servlet;
public interface HandlerMapping {
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
7、HandlerMapping是什么?HandlerExecutionChain是什么?
那么,新的问题来了,HandlerMapping要做什么?
HandlerMapping会通过url,把这url请求映射成为HandlerExecutionChain。
这又是什么东东?其实这是设计模式中的责任链模式,说的直白一点,就是两个东西:
(1)handler
(2) chain链 里面全是拦截器HandlerInterceptor
通过这种方式,让HandlerMapping成为或者串联一一大堆可以控制的组件。
特别注意,模板责任链这种设计模式,是HandlerMapping的关键思路。
针对springMVC请求处理这一块,你只需要记住:url穿马甲,马甲绑了责任链。
(3)封装
只负责找,却不负责执行,执行交给处理器或适配器做。
HandlerMapping是处理器映射器,根据请求找到处理器Handler,但并不是简单的返回处理器,而是将处理器和拦截器封装,形成一个处理器执行链(HandlerExecuteChain)。
HandlerMapping执行流程如下:
DispatcherServlet
--->doDispatcher()
---->getHandler(request):
---->HandlerExecutionChain
------> hm.getHandler(request)-----》方法体中
----->ExecutionChain executionChain = getHandlerExecutionChain(handler, request);
----->new HandlerExecutionChain(handler)
----->chain.addInterceptor(interceptor);
8、适配器
HandlerAdapter适配器,今天没时间了,改天聊。
---------------------------------
接着写适配器,了解这个之前,要知道设计模式中的适配器模式。这是个什么东西呢?
码代码的人应该有人买过美版电脑吧,插座上都有一个适配器。
对,你理解的不错,就那个东西。
适配器模式也和这个适配器大差不差。
简单的说,就是你直接插,插不上,我给你做个转换器用用。
这个HandlerAdapter就是后三国的赵云。
到了这里,就需要明白HandlerAdapter到底干了什么?
9、适配器到底干了什么?
HandlerAdapter解决了一个问题,即如何处理请求的策略。
public interface HandlerAdapter {
//判断是否支持传入的Handler
boolean supports(Object handler);
//用来使用Handler处理请求
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
//用来获取资料的Last-Modified值
long getLastModified(HttpServletRequest request, Object handler);
}
具体来说:
(1)通过请求url、请求Method和requestMapping定义,最终确定使用处理类的哪个方法来处理请求。
(2)确定如何转换需要的参数传入调用方法
(3)最终调用返回ModelAndView。
(4) 通过调用handlerAdapter中的handler方法
总结下:
一、handlerAdapter这个类的作用就是接过handlermapping解析请求得到的handler对象。在更精确的定位到能够执行请求的方法。
具体来说:
二、根据handlerMapping传过来的Handler对象,DispatcherServlet将自己的HandlerAdapter集合与之一一匹配。如果有支持Handler对象的HandlerAdapter,那么HandlerAdapter就会调用自己的 handle方法处理请求。
10、适配器的工作流程工作流程
(1)DispatcherServlte会根据handlerMapping传过来的controller与已经注册好了的HandlerAdapter 一一匹配,看哪一种HandlerAdapter是支持该controller类型的。
(2)如果找到了其中一种HandlerAdapter是支持传过来的 controller类型,那么该HandlerAdapter会调用自己的handle方法。
(3)HandlerAdapter的handle只是做了一些模板化的工作。最终依然是通过反射调用了controller的自我实现代码。
(4)这里有一个类值得研究:RequestMappingHandlerAdapter。因为它真正意义上实现了HandlerAdapter 接口定义的功能。
handleInternal() 负责调用 HandlerMethod(处理器),并返回 ModelAndView。
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response,
HandlerMethod handlerMethod) throws Exception {
// 1.校验请求
// 检查是否支持当前 rqeuest 的 method 和 session
checkRequest(request);
// 2.判断控制器是否存在 @SessionAttributes 注解
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
// 2.1设置缓存
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
// 2.2准备响应
prepareResponse(response);
}
// 默认为 false,为 true 表示在同步块中执行 invokeHandlerMethod
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return invokeHandlerMethod(request, response, handlerMethod);
}
}
}
// 关键 -> 3.处理器调用
return invokeHandlerMethod(request, response, handlerMethod);
}
private ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response,HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
//执行Controller中的RequestMapping注释的方法
requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
else {
ModelMap model = mavContainer.getModel();
//返回ModelAndView视图
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
}
11、视图解析器
======大头基本结束,有空在写视图,目前大部分前后端分离,其实给json就挺好的。