spring mvc 处理流程源码解析

整体处理流程
在这里插入图片描述

1. 接收请求

org.springframework.web.servlet.FrameworkServlet#initContextHoldersRequestContextHolder就是利用ThreadLocal,将request放到线程关联的ThreadLocal中

RequestContextHolder,是springmvc的工具类,持有上下文request的容器,从而使得可以在任何java代码处获取request对象

2. 寻找HandlerMapping,关联HandlerMethod(@Controller)

确定这个请求需要被哪个@Controller的哪个方法处理

3. 生成处理器执行链

org.springframework.web.servlet.DispatcherServlet#doDispatch

// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);

获得到mappedHandler
在这里插入图片描述
位于处理器链末端的是一个HandlerMethod,DispatcherServlet通过handlerAdapter适配器对Interceptor List和HandlerMethod进行封装,并按照统一的适配器接口对HandlerAdapter处理方法进行调用

4. 处理器适配

根据HandlerMethod寻找HandlerAdapter

HandlerAdatper作用:帮助DispatcherServlet调用请求处理器(HandlerMethod),无需关注其中实际的调用细节。比如,调用注解实现的@Controller需要解析其关联的注解,比如请求参数绑定,类型转换,校验等,HandlerAdapter的主要目的是为了屏蔽与DispatcherServlet之间的诸多细节,下面的5-7步都是其作用的体现

5. handlerMethod转换

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
		implements BeanFactoryAware, InitializingBean {
    
    // 其使用一个Composite组合对象来装载多个HandlerMethodArgumentResolver
    private HandlerMethodArgumentResolverComposite argumentResolvers;
}

其使用一个Composite组合对象来装载多个HandlerMethodArgumentResolver

方法参数解析器:HandlerMethodArgumentResolver
将请求参数映射到比如@RequestParam、@PathVariable以及@RequestBody
其也是有多个,哪个支持就处理

public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
    
    private final List<HandlerMethodArgumentResolver> argumentResolvers = new LinkedList<>();
}

线程栈
在这里插入图片描述
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod

这是第一次进入到invokeHandlerMethod

ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
    invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
    invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.invokeAndHandle(webRequest, mavContainer);

其同时也会装载多个HandlerMethodReturnValueHandlers
调用RequestMappingHandlerAdapter#invokeHandlerMethod

6. 处理请求

7. 通过HandlerMethodArgumentResolver来解析方法参数

参考:springmvc参数收集与类型转换源码解析

8. 执行到具体的Controller中,执行方法

回到doDispatcher方法,线程栈弹出

// Apply preHandle methods of registered interceptors. 
// 执行interceptor preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    return;
}

// Actually invoke the handler.
// 调用目标controller的目标method
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

// Apply postHandle methods of registered interceptors.
// 执行interceptor postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);

在这里插入图片描述
再一次执行invokeHandlerMethod方法
HandlerExecutionChain#applyPreHandle方法中循环执行各个interceptor,最后通过反射调用方法

/**
 * Invoke the handler method with the given argument values.
 * 真实调用controller中的方法
 */
protected Object doInvoke(Object... args) throws Exception {
    ReflectionUtils.makeAccessible(getBridgedMethod());
    try {
        // 通过反射调用方法
        return getBridgedMethod().invoke(getBean(), args);
    }
}

获取到返回值

9. 处理HandlerMethod执行结果

接上面的源码分析

->

返回到org.springframework.web.servlet.DispatcherServlet#doDispatch

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

->

org.springframework.web.servlet.DispatcherServlet#processDispatchResult

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

->
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle方法

try {
    this.returnValueHandlers.handleReturnValue(
        returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}

在这里插入图片描述
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor#writeWithMessageConverters

for (HttpMessageConverter<?> converter : this.messageConverters) {
    // if canWrite 。。。
    if(converter.canWrite(valueType, selectedMediaType)){
        genericConverter.write(outputValue, declaredType, selectedMediaType, outputMessage);
    }        
}

在这里插入图片描述
注意:

  • RequestResponseBodyMethodProcessor这个HandlerMethodReturnValueHandler包含多个HttpMessageConverter
  • RequestResponseBodyMethodProcessor,其既是请求参数的解析器,又是执行结果的处理器。
  • 可以自定义实现HandlerMethodArgumentResolver以及HandlerMethodReturnValueHandler但是要注意其顺序

10. 转化Http消息。Render the given ModelAndView。这里涉及到视图内容协商。

内容协商处理流程
在这里插入图片描述
前面的5步已经在前面已经做了

从上图的第6步:解析@ResponseBody HandlerMethod返回值开始分析

处理Accept Header,解析MediaType,对前端请求需要的(请求的媒体类型),与后端可以生成的(可生成的媒体类型),进行Compatible兼容处理,获得到协商好的MediaType

注意:当不包含Accept请求头的时候,其会返回*/*,即所有的媒体类型,与所有的producible media types兼容,这也就是为什么我们一般在发送http请求的时候不需要设置accept header的原因

org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#handleReturnValue

writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);

->

org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor#writeWithMessageConverters

List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);

->

private List<MediaType> getAcceptableMediaTypes(HttpServletRequest request)
    throws HttpMediaTypeNotAcceptableException {

    return this.contentNegotiationManager.resolveMediaTypes(new ServletWebRequest(request));
}

在这里插入图片描述
HeaderContentNegotiationStrategy就是会处理Accept Header

第7步:匹配HttpMessageConverter支持的媒体类型

如果@RequestMapping.produces()存在,返回指定MediaType列表否则,返回已注册的HttpMessageConverter列表中支持的MediaType列表

返回到writeWithMessageConverters方法
在这里插入图片描述

for (MediaType requestedType : requestedMediaTypes) {
    for (MediaType producibleType : producibleMediaTypes) {
        // 需要的 与 可以生成的 Compatible
        if (requestedType.isCompatibleWith(producibleType)) {
            mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
        }
    }
}

这里就获得到了协商好的媒体类型了

for (HttpMessageConverter<?> converter : this.messageConverters) {
    
    // 如果能写
    genericConverter.write(outputValue, declaredType, selectedMediaType, outputMessage);
}

11. 返回REST HTTP

/**
	 * This implementation sets the default headers by calling {@link #addDefaultHeaders},
	 * and then calls {@link #writeInternal}.
	 */
public final void write(final T t, @Nullable final Type type, @Nullable MediaType contentType,
                        HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {

    // 把响应里面的头加上去 会得到一个响应头中的Content-Type: application/json
    final HttpHeaders headers = outputMessage.getHeaders();
    addDefaultHeaders(headers, t, contentType);

    writeInternal(t, type, outputMessage);
    outputMessage.getBody().flush();
}

->

org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#writeInternal

MediaType contentType = outputMessage.getHeaders().getContentType();
JsonEncoding encoding = getJsonEncoding(contentType);

JsonGenerator generator = this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);

// object就是返回的pojo
Object value = object;
objectWriter.writeValue(generator, value);

这一步已经处理完成response了

->

最后回到org.springframework.web.servlet.DispatcherServlet#processDispatchResult,调用interceptor.afterCompletion方法

// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
    render(mv, request, response);
}
// 返回json 其mv = null
// 会调用interceptor.afterCompletion方法
mappedHandler.triggerAfterCompletion(request, response, null);

在整个过程中,注意到HandlerInterceptor的三个方法,preHandle,postHandle以及afterComplete的调用时机

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值