SpringBoot 请求处理流程

一、简介

SpringBoot 请求处理流程主要分为四部分:请求分发、映射处理器、调用处理器方法。

二、请求分发

每当 SpringBoot 收到接口请求后,首先就是进入 tomcat 的DispatcherServlet#doService方法,通过doDispatch进行请求分发。

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // set attribute to request
    try {
        doDispatch(request, response);
    }
    finally {
    }
}

三、映射处理器

请求分发的第一步就是映射处理器。通过getHandler方法遍历handlerMappings,通过HandlerMapping获取请求处理器。对于当前接口请求采用的是RequestMappingHandlerMapping。拿到处理器对象后,就可以调用接口方法。

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 {
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);
            // Determine handler for the current request.
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }
            // Determine handler adapter for the current request.
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // Actually invoke the handler.
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        } catch (Exception ex) {
            dispatchException = ex;
        }
    }
}
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

handlerMappings中默认支持5个映射器,它们都是在项目启动时生成的。

四、调用处理器方法

调用处理器对象时,首先会将处理器对象强转为处理器方法对象HandlerMethod。接着,调用请求处理器方法。通过断点深入发现,主要工作流程如下:

ServletInvocableHandlerMethod#invokeAndHandle ->
InvocableHandlerMethod#invokeForRequest

在ServletInvocableHandlerMethod中通过invokeAndHandle调用处理器方法,获取返回值写入response。其中,又会调用父类InvocableHandlerMethod的invokeForRequest。在invokeForRequest中去获取请求的参数列表。

获取参数列表

通过断点深入发现,获取请求参数列表是通过InvocableHandlerMethod#invokeForRequest。

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
    // 获取请求参数
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    if (logger.isTraceEnabled()) {
        logger.trace("Arguments: " + Arrays.toString(args));
    }
    return doInvoke(args);
}

在getMethodArgumentValues中,会遍历每一个参数,尝试获取解析器进行解析。

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {

    MethodParameter[] parameters = getMethodParameters();
    if (ObjectUtils.isEmpty(parameters)) {
        return EMPTY_ARGS;
    }

    Object[] args = new Object[parameters.length];
    for (int i = 0; i < parameters.length; i++) {
        MethodParameter parameter = parameters[i];
        parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
        args[i] = findProvidedArgument(parameter, providedArgs);
        if (args[i] != null) {
            continue;
        }
        if (!this.resolvers.supportsParameter(parameter)) {
            throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
        }
        try {
            // 解析每一个参数
            args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
        }
        catch (Exception ex) {
            throw ex;
        }
    }
    return args;
}

参数的解析是通过遍历上下文的argumentResolvers来获取支持的解析器,并将解析器缓存,这样后面的参数解析器就可以直接从缓存中获取。

public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    // 获取解析器
    HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
    if (resolver == null) {
        throw new IllegalArgumentException("Unsupported parameter type [" +
                parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
    }
    // 解析参数
    return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}

private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
        HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
    if (result == null) {
        // 获取支持的解析器,并写入缓存
        for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
            if (resolver.supportsParameter(parameter)) {
                result = resolver;
                this.argumentResolverCache.put(parameter, result);
                break;
            }
        }
    }
    return result;
}

默认的26个参数解析器如下,本次请求采用的是RequestResponseBodyMethodProcessor解析器。

获取解析器之后,下面就是对参数进行解析。参数的解析通过MessageConverter将文本解析成相应的参数对象。

public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

    parameter = parameter.nestedIfOptional();
    // 读取MessageConverter解析结果
    Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
    String name = Conventions.getVariableNameForParameter(parameter);
    return adaptArgumentIfNecessary(arg, parameter);
}

参数的解析流程就是遍历每一个参数,获取合适的解析器对参数进行解析。程序会缓存参数和对应的解析器,而具体的解析细节依赖MessageConverter来实现。

调用处理器方法

protected Object doInvoke(Object... args) throws Exception {
    ReflectionUtils.makeAccessible(getBridgedMethod());
    try {
        // 调用处理器方法
        return getBridgedMethod().invoke(getBean(), args);
    }
    catch (IllegalArgumentException ex) {
    }
}

获取返回结果

获取返回结果首先会解析返回值的类型,通过遍历上下文中的returnValueHandlers获取支持的返回值处理器。

private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
    boolean isAsyncValue = isAsyncReturnValue(value, returnType);
    for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
        if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
            continue;
        }
        if (handler.supportsReturnType(returnType)) {
            return handler;
        }
    }
    return null;
}

默认支持的返回值处理器如下:
在这里插入图片描述

拿到返回值处理器后,调用handleReturnValue方法将返回结果写入响应对象中,写入细节还是依赖MessageConverter支持。

// handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
    mavContainer.setRequestHandled(true);
    ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
    ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

    // Try even with null return value. ResponseBodyAdvice could get involved.
    writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

获取返回结果的工作流程是获取合适的返回值处理器,然后调用返回值处理器方法,将结果通过MessageConverter写入到响应对象中。

五、总结

SpringBoot 接口方法的大致工作流程:

  1. Servlet接口分发
  2. 映射处理器方法
    获取上下文的HandlerMapping,根据请求参数映射处理器方法。
  3. 调用处理器方法
    a. 通过上下文的参数解析器解析参数,具体解析细节依赖MessageConverter。
    b. 调用处理器方法引用调用方法。
    c. 通过上下文的返回结果处理器处理返回值,依赖MessageConverter将返回值写入响应对象中。
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Boot 中,请求的执行流程可以分为以下几个步骤: 1. 客户端发送请求到服务器,请求到达 DispatcherServlet。 2. DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的处理器 Handler。 3. 根据 Handler 信息,调用适当的 HandlerAdapter 进行处理处理。 4. 处理器 Handler 处理请求,生成 ModelAndView 对象,包含模型数据和视图信息。 5. HandlerAdapter 将处理处理的结果 ModelAndView 返回给 DispatcherServlet。 6. DispatcherServlet 根据 ModelAndView 中的视图信息,调用 ViewResolver,解析出视图对象。 7. 最终视图对象被渲染并返回给客户端。 具体来说,每个步骤的执行过程如下: 1. 客户端发送请求到服务器,请求到达 DispatcherServlet。 - DispatcherServlet 是 Spring MVC 的核心控制器,接收所有的请求,并将请求分发给相应的处理器进行处理。 - DispatcherServlet 可以通过配置文件或注解配置来进行自定义设置。 2. DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的处理器 Handler。 - HandlerMapping 是用来解析请求 URL 和处理器的对应关系的。 - Spring Boot 中默认使用的是 RequestMappingHandlerMapping。 - HandlerMapping 会根据请求信息,查找匹配的处理器 Handler。 3. 根据 Handler 信息,调用适当的 HandlerAdapter 进行处理处理。 - HandlerAdapter 是用来处理处理器 Handler 的适配器。 - Spring Boot 中默认使用的是 RequestMappingHandlerAdapter。 - HandlerAdapter 会根据 Handler 的类型,调用对应的方法进行处理。 4. 处理器 Handler 处理请求,生成 ModelAndView 对象,包含模型数据和视图信息。 - 处理器 Handler 是真正处理请求的对象。 - 处理器 Handler 可以是一个普通的 Java 类,也可以是一个注解了 @Controller 或 @RestController 的类。 - 处理器 Handler 会根据请求参数进行处理,并生成 ModelAndView 对象。 - ModelAndView 对象包含了模型数据和视图信息。 5. HandlerAdapter 将处理处理的结果 ModelAndView 返回给 DispatcherServlet。 - HandlerAdapter 将处理器 Handler 处理的结果 ModelAndView 对象返回给 DispatcherServlet。 - ModelAndView 对象包含了模型数据和视图信息。 6. DispatcherServlet 根据 ModelAndView 中的视图信息,调用 ViewResolver,解析出视图对象。 - ViewResolver 是用来解析视图名称的。 - Spring Boot 中默认使用的是 InternalResourceViewResolver。 - ViewResolver 会将视图名称解析成实际的视图对象。 7. 最终视图对象被渲染并返回给客户端。 - 视图对象会根据模型数据进行渲染,并生成响应结果。 - 最终响应结果会通过 HttpServletResponse 对象返回给客户端。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JFS_Study

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值