Java spring mvc请求详情介绍

网友投稿 238 2022-08-17


Java spring mvc请求详情介绍

目录一、源码执行流程二、源码执行流程图三、spring mvc中的一核心组件四、源码分析五、获取组件相关逻辑:六、获取参数,执行方法源码分析七、渲染视图逻辑

前言:

本文源码基于spring-framework-5.3.10。mvc是spring源码中的一个子模块!

一、源码执行流程

用户发送请求至前端控制器DispatcherServlet。DispatcherServlet收到请求调用处理器映射器HandlerMapping。处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter,执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作执行处理器Handler(Controller,也叫页面控制器)。Handler执行完成返回ModelAndView、HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet。DispatcherServlet将ModelAndView传给ViewReslover视图解析器。ViewReslover解析后返回具体ViewDispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。DispatcherServlet响应用户。

二、源码执行流程图

三、spring mvc中的一核心组件

DispatcherServlet: 前端调度器 , 负责将请求拦截下来分发到各控制器方法中HandlerMapping: 负责根据请求的URL和配置@RequestMapping映射去匹配, 匹配到会返回Handler(具体控制器的方法)HandlerAdaper: 负责调用Handler-具体的方法- 返回视图的名字 Handler将它封装到ModelAndView(封装视图名,request域的数据)ViewReslover: 根据ModelAndView里面的视图名地址去找到具体的jsp封装在View对象中View:进行视图渲染(将jsp转换成html内容 --这是Servlet容器的事情了) 最终response到的客户端

四、源码分析

/**

* 最核心的控制器

* 源码位置:org.springframework.web.servlet.DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse)

*/

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

HttpServletRequest processedRequest = request;

HandlerExecutionChain mappedHandler = null;

boolean multipartRequestParsed = false;

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

try {

ModelAndView mv = null;

Exception dispatchException = null;

try {

// 验证是不是上传的请求,上传的请求会转化为MultipartHttpServletRequest

processedRequest = checkMultipart(request);

multipartRequestParsed = (processedRequest != request);

// 进行映射

mappedHandler = getHandler(processedRequest);

if (mappedHandler == null) {

noHandlerFound(processedRequest, response);

return;

}

// 找到最合适的HandlerAdapter,按照顺序,那个先解析到就是那个

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// Process last-modified header, if supported by the handler. HTTP缓存相关

String method = request.getMethod();

boolean isGet = HttpMethod.GET.matches(method);

if (isGet || HttpMethod.HEAD.matches(method)) {

long lastModified = ha.getLastModified(request, mappedHandler.getHandler());

if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {

return;

}

}

// 前置拦截器

if (!mappedHandler.applyPreHandle(processedRequest, response)) {

// 返回false就不进行后续处理了

return;

}

// Actually invoke the handler.

// 获取参数,执行方法

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {

return;

}

// 如果mv有 视图没有,给你设置默认视图

applyDefaultViewName(processedRequest, mv);

//后置拦截器

mappedHandler.applyPostHandle(processedRequest, response, mv);

}

catch (Exception ex) {

dispatchException = ex;

}

catch (Throwable err) {

// As of 4.3, we're processing Errors thrown from handler methods as well,

// making them available for @ExceptionHandler methods and other scenarios.

dispatchException = new NestedServletException("Handler dispatch failed", err);

}

// 渲染视图

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

}

catch (Exception ex) {

triggerAfterCompletion(processedRequest, response, mappedHandler, ex);

}

catch (Throwable err) {

triggerAfterCompletion(processedRequest, response, mappedHandler,

new NestedServletException("Handler processing failed", err));

}

finally {

if (asyncManager.isConcurrentHandlingStarted()) {

// Instead of postHandle and afterCompletion

if (mappedHandler != null) {

mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);

}

}

else {

// Clean up any resources used by a multipart request.

if (multipartRequestParsed) {

cleanupMultipart(processedRequest);

}

}

}

}

五、获取组件相关逻辑:

原理:谁先解析到就用谁!

/**

* 获取处理器映射器

* 源码位置:org.springframework.web.servlet.DispatcherServlet.getHandler(HttpServletRequest)

*/

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

if (this.handlerMappings != null) {

/** 拿到所有handlerMappings (容器启动阶段初始化:拿到所有实现了HandlerMapping的Bean)

* @see DispatcherServlet#initHandlerMappings

* 测试发现: 不同的HandlerMapping可以有相同path, 谁先解析到就用哪个

* */

for (HandlerMapping mapping : this.handlerMappings) {

HandlerExecutionChain handler = mapping.getHandler(request);

if (handler != null) {

return handler;

}

}

}

return null;

}

/**

* 获取处理器适配器

* 源码位置:org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(Object)

*/

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {

if (this.handlerAdapters != null) {

// 按照配置的顺序,谁先解析到就用那个

for (HandlerAdapter adapter : this.handlerAdapters) {

if (adapter.supports(handler)) {

return adapter;

}

}

}

throw new ServletException("No adapter for handler [" + handler +

"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");

}

六、获取参数,执行方法源码分析

/**

* 获取参数,执行方法最外层的调用

* 源码位置:org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(HttpServletRequest, HttpServletResponse, Object)

*/

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

// 直接调用这个方法

return handleInternal(request, response, (HandlerMethod) handler);

}

/**

* 获取参数,执行方法内部的调用逻辑

* 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(HttpServletRequest, HttpServletResponse, HandlerMethod)

*/

protected ModelAndView handleInternal(HttpServletRequest request,

HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

ModelAndView mav;

// 检查当前请求的method是否为支持的method(默认Null,可通过继承AbstractController设置supportedMethods)

// 检查当前请求是否必须session (默认false,可通过继承AbstractController设置requireSession)

checkRequest(request);

/**

* 判断当前是否需要支持在同一个session中只能线性地处理请求:一个session同时只能处理一个线程

* 因为锁是通过 synchronized 是 JVM 进程级,所以在分布式环境下,

* 无法达到同步相同 Session 的功能。默认情况下,synchronizeOnSession 为 false

*/

if (this.synchronizeOnSession) {

// 获取当前请求的session对象

HttpSession session = request.getSession(false);

if (session != null) {

// 为当前session生成一个唯一的可以用于锁定的key

Object mutex = WebUtils.getSessionMutex(session);

synchronized (mutex) {

// 对HandlerMethod进行参数等的适配处理,并调用目标handler

mav = invokeHandlerMethod(request, oyDMLQtIWDresponse, handlerMethod);

}

}

else {

// 如果当前不存在session,则直接对HandlerMethod进行适配

mav = invokeHandlerMethod(request, response, handlerMethod);

}

}

else {

// *如果当前不需要对session进行同步处理,则直接对HandlerMethod进行适配

mav = invokeHandlerMethod(request, response, handlerMethod);

}

//判断当前请求头中是否包含Cache-Control请求头,如果不包含,则对当前response进行处理

if (!response.containsHeader(HEADER_CACHE_CONTROL)) {

// 如果当前SessionAttribute中存在配置的attributes,则为其设置过期时间。

// 这里SessionAttribute主要是通过@SessionAttribute注解生成的

if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {

applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);

}

else {

// 如果当前不存在SessionAttributes,则判断当前是否存在Cache-Control设置,

// 如果存在,则按照该设置进行response处理,如果不存在,则设置response中的

// Cache的过期时间为-1,即立即失效

prepareResponse(response);

}

}

return mav;

}

/**

* 获取参数,执行方法前的准备逻辑

* 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(HttpServletRequest, HttpServletResponse, HandlerMethod)

*/

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,

HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

// 把我们的请求req resp包装成 ServletWebRequest

ServletWebRequest webRequest = new ServletWebRequest(request, response);

try {

// 获取容器中全局配置的InitBinder和当前HandlerMethod所对应的Controller中

// 配置的InitBinder,用于进行参数的绑定

WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);

// 获取容器中全局配置的ModelAttribute和当前HandlerMethod所对应的Controller 中配置的ModelAttribute,

// 这些配置的方法将会在目标方法调用之前进行调用

ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

// 封装handlerMethod,会在调用前解析参数、调用后对返回值进行处理

ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);

if (this.argumentResolvers != null) {

// 让invocableMethod拥有参数解析能力

invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);

}

if (this.returnValueHandlers != null) {

// 让invocableMethod拥有返回值处理能力

invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);

}

// 让invocableMethod拥有InitBinder解析能力

invocableMethod.setDataBinderFactory(binderFactory);

// 设置ParameterNameDiscoverer,该对象将按照一定的规则获取当前参数的名称

invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

// ModelAndView处理容器

ModelAndViewContainer mavContainer = new ModelAndViewContainer();

// 将request的Attribute复制一份到ModelMap

mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));

// *调用我们标注了@ModelAttribute的方法,主要是为我们的目标方法预加载

modelFactory.initModel(webRequest, mavContainer, invocableMethod);

// 重定向的时候,忽略model中的数据 默认false

mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

// 获取当前的AsyncWebRequest,这里AsyncWebRequest的主要作用是用于判断目标

// handler的返回值是否为WebAsyncTask或DeferredResult,如果是这两种中的一种,

// 则说明当前请求的处理应该是异步的。所谓的异步,指的是当前请求会将Controller中

// 封装的业务逻辑放到一个线程池中进行调用,待该调用有返回结果之后再返回到response中。

// 这种处理的优点在于用于请求分发的线程能够解放出来,从而处理更多的请求,提高吞吐。

// 只有待目标任务完成之后才会回来将该异步任务的结果返回。

AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);

asyncWebRequest.setTimeout(this.asyncRequestTimeout);

// 封装异步任务的线程池、request、interceptors到WebAsyncManager中

WebAsyncManagerhttp:// asyncManager = WebAsyncUtils.getAsyncManager(request);

asyncManager.setTaskExecutor(this.taskExecutor);

asyncManager.setAsyncWebRequest(asyncWebRequest);

asyncManager.registerCallableInterceptors(this.callableInterceptors);

asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

// 这里就是用于判断当前请求是否有异步任务结果的,如果存在,则对异步任务结果进行封装

if (asyncManager.hasConcurrentResult()) {

Object result = asyncManager.getConcurrentResult();

mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];

asyncManager.clearConcurrentResult();

LogFormatUtils.traceDebug(logger, traceOn -> {

String formatted = LogFormatUtils.formatValue(result, !traceOn);

return "Resume with async result [" + formatted + "]";

});

invocableMethod = invocableMethod.wrapConcurrentResult(result);

}

// *对请求参数进行处理,调用目标HandlerMethod,并且将返回值封装为一个ModelAndView对象

invocableMethod.invokeAndHandle(webRequest, mavContainer);

if (asyncManager.isConcurrentHandlingStarted()) {

return null;

}

// 对封装的ModelAndView进行处理,主要是判断当前请求是否进行了重定向,如果进行了重定向,

// 还会判断是否需要将FlashAttributes封装到新的请求中

return getModelAndView(mavContainer, modelFactory, webRequest);

}

finally {

webRequest.requestCompleted();

}

}

/**

* 获取参数,执行方法

* 源码位置:org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletWebRequest, ModelAndViewContainer, Objehttp://ct...)

*/

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,

Object... providedArgs) throws Exception {

/*真正的调用我们的目标对象 很重要 很重要*/

Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);

// 设置相关的返回状态

setResponseStatus(webRequest);

// 如果请求处理完成,则设置requestHandled属性

if (returnValue == null) {

if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {

disableContentCachingIfNecessary(webRequest);

mavContainer.setRequestHandled(true);

oyDMLQtIWD return;

}

}

// 如果请求失败,但是有错误原因,那么也会设置requestHandled属性

else if (StringUtils.hasText(getResponseStatusReason())) {

mavContainer.setRequestHandled(true);

return;

}

mavContainer.setRequestHandled(false);

Assert.state(this.returnValueHandlers != null, "No return value handlers");

try {

// 遍历当前容器中所有ReturnValueHandler,判断哪种handler支持当前返回值的处理,

// 如果支持,则使用该handler处理该返回值

this.returnValueHandlers.handleReturnValue(

returnValue, getReturnValueType(returnValue), mavContainer, webRequest);

}

catch (Exception ex) {

if (logger.isTraceEnabled()) {

logger.trace(formatErrorForReturnValue(returnValue), ex);

}

throw ex;

}

}

七、渲染视图逻辑

/**

* 渲染视图逻辑

* 源码位置:org.springframework.web.servlet.DispatcherServlet.processDispatchResult(HttpServletRequest, HttpServletResponse, HandlerExecutionChain, ModelAndView, Exception)

*/

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,

@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,

@Nullable Exception exception) throws Exception {

boolean errorView = false;

// 异常视图

if (exception != null) {

if (exception instanceof ModelAndViewDefiningException) {

logger.debug("ModelAndViewDefiningException encountered", exception);

mv = ((ModelAndViewDefiningException) exception).getModelAndView();

}

else {

Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);

mv = processHandlerException(request, response, handler, exception);

errorView = (mv != null);

}

}

// Did the handler return a view to render?

if (mv != null && !mv.wasCleared()) {

// 解析、渲染视图:解析视图名,拼接前后缀

render(mv, request, response);

if (errorView) {

WebUtils.clearErrorRequestAttributes(request);

}

}

else {

if (logger.isTraceEnabled()) {

logger.trace("No view rendering, null ModelAndView returned.");

}

}

if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {

// Concurrent handling started during a forward

return;

}

if (mappedHandler != null) {

// Exception (if any) is already handled.. 拦截器:AfterCompletion

mappedHandler.triggerAfterCompletion(request, response, null);

}

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java spring mvc处理器映射器介绍
下一篇:Netty分布式flush方法刷新buffer队列源码剖析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~