首页 > 其他分享 >揭秘Spring Boot的请求处理全流程:从启动到响应的奥秘

揭秘Spring Boot的请求处理全流程:从启动到响应的奥秘

时间:2024-11-25 12:05:22浏览次数:3  
标签:context Spring request class Boot response DispatcherServlet Servlet 揭秘

前言

在 Spring Boot 中,一个简单的接口@RestController,就能轻松地实现复杂的Web服务。当我们在浏览器中访问http://localhost:8080/user/all,返回一个简单的字符串"all user",背后究竟发生了什么?

从Spring Boot启动时的自动配置,到内嵌的Servlet容器启动,再到DispatcherServlet的初始化,以及请求如何一步步被映射、执行,最终生成响应。

本文将以一个简单的示例接口为切入点,聊一聊Spring Boot从接收请求到生成响应的完整处理流程。

一、SprinngBoot启动阶段

1.1WebMvc自动配置

1.1.1自动配置类路径

image-20241121194236998

1.1.2自动配置类注解

  • 类上注解

    1. // SpringMVC的配置在DispatcherServlet、任务执行器、校验器等基础配置完成后加载,保证依赖关系
      @AutoConfiguration(after = { DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
      		ValidationAutoConfiguration.class })
      
    2. // 条件注解,当前应用是基于Servlet的Web应用时,才会激活这个自动配置类
      @ConditionalOnWebApplication(type = Type.SERVLET)
      
    3. // 条件注解,类路径下有Servlet, DispatcherServlet, WebMvcConfigurer时才激活这个自动配置类
      // Servlet是Servlet API的核心类,DispatcherServlet, WebMvcConfigurer是Spring MVC的核心 Servlet和扩展配置接口
      @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
      
    4. // 条件注解,容器中不存在WebMvcConfigurationSupport这个bean时,才激活这个自动配置类
      @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
      
    5. // 确保WebMvcAutoConfiguration在绝大多数自动配置类之前加载,但仍为DispatcherServlet等基础配置留出更高的优先级。
      @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
      
@AutoConfiguration(after = { DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
		ValidationAutoConfiguration.class })
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
public class WebMvcAutoConfiguration {
	// 省略部分代码...
}

  • 自动配置类中静态内部类EnableWebMvcConfiguration

  • EnableWebMvcConfiguration继承了WebMvcConfigurationSupport,WebMvcConfigurationSupport中@Bean注解的bean也会处理

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WebProperties.class)
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {

    // 省略部分代码...

    @Bean
    @Override
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
            @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
            @Qualifier("mvcConversionService") FormattingConversionService conversionService,
            @Qualifier("mvcValidator") Validator validator) {
        RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager,
                conversionService, validator);
        adapter.setIgnoreDefaultModelOnRedirect(
                this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
        return adapter;
    }

	// 省略部分代码...
}
// WebMvcConfigurationSupport
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
    // 省略部分代码...
    
    @Bean
	public RequestMappingHandlerMapping requestMappingHandlerMapping(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

		RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
		mapping.setOrder(0);
		mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
		mapping.setContentNegotiationManager(contentNegotiationManager);
		mapping.setCorsConfigurations(getCorsConfigurations());

		PathMatchConfigurer pathConfig = getPathMatchConfigurer();
		if (pathConfig.getPatternParser() != null) {
			mapping.setPatternParser(pathConfig.getPatternParser());
		} else {
			mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
			mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());

			Boolean useSuffixPatternMatch = pathConfig.isUseSuffixPatternMatch();
			if (useSuffixPatternMatch != null) {
				mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
			}
			Boolean useRegisteredSuffixPatternMatch = pathConfig.isUseRegisteredSuffixPatternMatch();
			if (useRegisteredSuffixPatternMatch != null) {
				mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
			}
		}
		Boolean useTrailingSlashMatch = pathConfig.isUseTrailingSlashMatch();
		if (useTrailingSlashMatch != null) {
			mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
		}
		if (pathConfig.getPathPrefixes() != null) {
			mapping.setPathPrefixes(pathConfig.getPathPrefixes());
		}

		return mapping;
	}
    
    // 省略部分代码...
}

1.1.3RequestMappingHandlerAdapter适配器

详细职责

  • 适配控制器方法
    1. 不同类型的处理器(如控制器方法、返回值等)需要不同的适配逻辑。
    2. RequestMappingHandlerAdapter专门适配使用@RequestMapping标注的方法。
  • 参数解析
    1. 提供一组HandlerMethodArgumentResolver,解析控制器方法参数:
      • @RequestParam、@PathVariable注解的参数。
      • HTTP请求体(如JSON)解析成对象。
      • 当前的HttpServletRequest、HttpSession等内置参数。
  • 返回值处理
    1. 提供一组HandlerMethodReturnValueHandler,处理控制器方法的返回值:
      • 将对象序列化为JSON。
      • 返回View对象进行渲染。
  • 调用控制器方法
    1. 根据解析好的参数,执行控制器方法。
    2. 将返回值通过适配器处理并返回给客户端。

参数解析器及返回值解析器从哪儿来

  1. // RequestMappingHandlerAdapter实现了InitializingBean。
    public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
    		implements BeanFactoryAware, InitializingBean {}
    
  2. 重写的afterPropertiesSet方法会在SpringBoot启动时,对实例requestMappingHandlerAdapter进行初始化阶段执行。

  3. afterPropertiesSet中添加了默认的参数解析器及返回值解析器

image-20241122153546994

1.1.4RequestMappingHandlerMapping请求映射

详细职责

  • 扫描并注册映射关系
    1. 启动时扫描所有标注了@RequestMapping的控制器类和方法。
    2. 解析为映射信息(RequestMappingInfo),并存储到内部的数据结构中。
  • 匹配映射关系
    1. 当请求到达时,根据URL路径、HTTP方法等信息,从缓存中快速匹配对应的控制器方法(HandlerMethod)。

扫描及注册

  • RequestMappingHandlerMapping间接实现了InitializingBean,所以在RequestMappingHandlerMapping初始化时也会执行afterPropertiesSet方法。

image-20241122154827805

  • afterPropertiesSet会调用父类AbstractHandlerMethodMapping的afterPropertiesSet方法

image-20241122155432651

  • processCandidateBean方法会遍历候选bean,把带有@Controller或者@RequestMapping注解类中带有@RequestMapping注解的方法筛选出来。

image-20241122160113563

image-20241122160218188

  • 处理方法映射注册

image-20241122160659772

1.2DispatcherServlet自动配置

1.2.1自动配置类路径

image-20241122163803690

1.2.2自动配置类注解

  • 类上注解

    1. // 优先级最高,最先处理该配置类
      @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
      
    2. // 在ServletWebServerFactoryAutoConfiguration处理后进行自动配置处理
      @AutoConfiguration(after = ServletWebServerFactoryAutoConfiguration.class)
      
    3. // 条件注解,当前应用是基于Servlet的Web应用时,才会激活这个自动配置类
      @ConditionalOnWebApplication(type = Type.SERVLET)
      
    4. // 类路径下有DispatcherServlet时才激活这个自动配置类
      @ConditionalOnClass(DispatcherServlet.class)
      
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@AutoConfiguration(after = ServletWebServerFactoryAutoConfiguration.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
public class DispatcherServletAutoConfiguration {
    // 省略部分代码...
}

内部静态配置类DispatcherServletConfiguration

  • 创建和配置DispatcherServlet实例。
protected static class DispatcherServletConfiguration {
    @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
        DispatcherServlet dispatcherServlet = new DispatcherServlet();
        dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
        dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
        dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
        dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
        dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
        return dispatcherServlet;
	}
}

内部静态配置类DispatcherServletRegistrationConfiguration

  • 注册一个DispatcherServlet的bean,设置初始配置,熟悉的loadOnStartup。Servlet启动时,servlet的启动顺序。
  • 这个阶段还在Spring容器中。
protected static class DispatcherServletRegistrationConfiguration {

    @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
    @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
            WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
        DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
                webMvcProperties.getServlet().getPath());
        registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
        registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
        multipartConfig.ifAvailable(registration::setMultipartConfig);
        return registration;
    }
}
  • 当tomcat容器(默认情况下)启动时,Servlet容器会调用所有ServletContextInitializer实现的onStartup方法。
image-20241122171626755
  • onStartup方法
// RegistrationBean
public final void onStartup(ServletContext servletContext) throws ServletException {
    String description = getDescription();
    if (!isEnabled()) {
        logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
        return;
    }
    register(description, servletContext);
}
  • 将DispatcherServlet注册到Servlet容器
// ServletRegistrationBean
protected ServletRegistration.Dynamic addRegistration(String description, ServletContext servletContext) {
    String name = getServletName();
    return servletContext.addServlet(name, this.servlet);
}

二、接口访问阶段

2.1tomcat处理传入的请求

// StandardWrapperValve
public void invoke(Request request, Response response) throws IOException, ServletException {
	// servlet实例不可用时,分配一个servlet实例处理请求
    servlet = wrapper.allocate();
    
}

2.1.1初始化servlet

// StandardWrapper
public Servlet allocate() throws ServletException {
    
    initServlet(instance);
}
// HttpServletBean
public final void init() throws ServletException {
    // 省略部分代码...

    // 这里是留给子类(FrameworkServlet)做初始化的
    initServletBean();
}
  • 控制台日志开始的地方

image-20241125101741268

web应用上下文已经在SpringBoot启动阶段创建,这里只是负责进行一些初始化工作

// FrameworkServlet
protected final void initServletBean() throws ServletException {
    getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
    if (logger.isInfoEnabled()) {
        logger.info("Initializing Servlet '" + getServletName() + "'");
    }
    long startTime = System.currentTimeMillis();

    try {
        this.webApplicationContext = initWebApplicationContext();
        initFrameworkServlet();
    }
    catch (ServletException | RuntimeException ex) {
        logger.error("Context initialization failed", ex);
        throw ex;
    }

    if (logger.isDebugEnabled()) {
        String value = this.enableLoggingRequestDetails ?
                "shown which may lead to unsafe logging of potentially sensitive data" :
                "masked to prevent unsafe logging of potentially sensitive data";
        logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
                "': request parameters and headers will be " + value);
    }

    if (logger.isInfoEnabled()) {
        logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
    }
}

protected WebApplicationContext initWebApplicationContext() {
    WebApplicationContext rootContext =
            WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;

    if (this.webApplicationContext != null) {
        // A context instance was injected at construction time -> use it
        wac = this.webApplicationContext;
        
        // 省略部分代码...
        
        ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
        
        // 省略部分代码...
    }
    // 省略部分代码...

    if (!this.refreshEventReceived) {
        // 手动触发刷新(做一些初始化工作)
        synchronized (this.onRefreshMonitor) {
            onRefresh(wac);
        }
    }

    if (this.publishContext) {
        // Publish the context as a servlet context attribute.
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }

    return wac;
}

2.1.2干了哪些初始化工作

  • 初始化 MultipartResolver,用于处理文件上传
  • 初始化 LocaleResolver,用于处理国际化
  • 初始化 ThemeResolver,用于处理主题
  • 初始化 HandlerMappings,用于处理请求映射
  • 初始化 HandlerAdapters,用于处理请求适配
  • 初始化 HandlerExceptionResolvers,用于处理异常解析
  • 初始化 RequestToViewNameTranslator,用于将请求翻译为视图名称
  • 初始化 ViewResolvers,用于解析视图
  • 初始化 FlashMapManager,用于处理 Flash 映射
// DispatcherServlet
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}

protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
}
2.1.2.1初始化HandlerMappings
  • 查找ApplicationContext中的所有处理器映射(包括父容器的)
private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;

    if (this.detectAllHandlerMappings) {
        Map<String, HandlerMapping> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            // We keep HandlerMappings in sorted order.
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
    
    // 省略部分代码...
    
	// 如果没有找到其他映射,通过注册一个默认的HandlerMapping来确保至少有一个HandlerMapping。
    if (this.handlerMappings == null) {
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }
	// 如果至少有一个HandlerMapping使用了路径模式,解析请求路径的功能将被启用
    for (HandlerMapping mapping : this.handlerMappings) {
        if (mapping.usesPathPatterns()) {
            this.parseRequestPath = true;
            break;
        }
    }
}
  • 所有的处理器映射

image-20241121152221842

2.1.2.2初始化HandlerAdapters
  • 查找ApplicationContext中的所有处理器适配器(包括父容器的)
private void initHandlerAdapters(ApplicationContext context) {
    this.handlerAdapters = null;

    if (this.detectAllHandlerAdapters) {
        Map<String, HandlerAdapter> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerAdapters = new ArrayList<>(matchingBeans.values());
            AnnotationAwareOrderComparator.sort(this.handlerAdapters);
        }
    }
	
    // 省略部分代码...
    
    //如果没有找到其他适配器,通过注册默认的HandlerAdapters来确保至少有一些HandlerAdapters。
    if (this.handlerAdapters == null) {
        this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }
}

image-20241121152607486

2.1.3开始请求

// StandardWrapperValue
public void invoke(Request request, Response response) throws IOException, ServletException {
	filterChain.doFilter(request.getRequest(), response.getResponse());
}

image-20241125103143706

2.1.3.1拦截器链调用
  • 如果有拦截器,先调用拦截器
  • 处理完拦截器,跳出拦截器连后,调用servlet实例(servlet的service方法)
// ApplicationFilterChain
private void internalDoFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException {

    // 存在拦截器,则调用
    if (pos < n) {
        ApplicationFilterConfig filterConfig = filters[pos++];
        try {
            Filter filter = filterConfig.getFilter();

            if (request.isAsyncSupported() &&
                    "false".equalsIgnoreCase(filterConfig.getFilterDef().getAsyncSupported())) {
                request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
            }
            if (Globals.IS_SECURITY_ENABLED) {
                final ServletRequest req = request;
                final ServletResponse res = response;
                Principal principal = ((HttpServletRequest) req).getUserPrincipal();

                Object[] args = new Object[] { req, res, this };
                SecurityUtil.doAsPrivilege("doFilter", filter, classType, args, principal);
            } else {
                filter.doFilter(request, response, this);
            }
        } catch (IOException | ServletException | RuntimeException e) {
            throw e;
        } catch (Throwable e) {
            e = ExceptionUtils.unwrapInvocationTargetException(e);
            ExceptionUtils.handleThrowable(e);
            throw new ServletException(sm.getString("filterChain.filter"), e);
        }
        return;
    }

    // 跳出拦截器链,调用servlet实例
    try {
        if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
            lastServicedRequest.set(request);
            lastServicedResponse.set(response);
        }

        if (request.isAsyncSupported() && !servletSupportsAsync) {
            request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
        }
        if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse) &&
                Globals.IS_SECURITY_ENABLED) {
            final ServletRequest req = request;
            final ServletResponse res = response;
            Principal principal = ((HttpServletRequest) req).getUserPrincipal();
            Object[] args = new Object[] { req, res };
            SecurityUtil.doAsPrivilege("service", servlet, classTypeUsedInService, args, principal);
        } else {
            // servlet的service方法
            servlet.service(request, response);
        }
    } catch (IOException | ServletException | RuntimeException e) {
        throw e;
    } catch (Throwable e) {
        e = ExceptionUtils.unwrapInvocationTargetException(e);
        ExceptionUtils.handleThrowable(e);
        throw new ServletException(sm.getString("filterChain.servlet"), e);
    } finally {
        if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
            lastServicedRequest.set(null);
            lastServicedResponse.set(null);
        }
    }
}
  • servlet的service方法
// FrameworkServlet
protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
    HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
    if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
        processRequest(request, response);
    } else {
        super.service(request, response);
    }
}

protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
    processRequest(request, response);
}

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

    doService(request, response);
}
2.1.3.2正式通过DispatcherServlet处理请求
// DispatcherServlet
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		logRequest(request);
    doDispatch(request, response);
}
  • 确定handler
  • 确定handler adapter
// DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 省略部分代码...
     
    // 确定当前请求的处理器
    mappedHandler = getHandler(processedRequest);
    
    // 确定当前请求的处理器适配器
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
    // 实际调用
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
    // 省略部分代码...
    
}
  • getHandler

image-20241125105425819

  • getHandlerAdapter

image-20241125105628039

  • handle

三、总结

3.1Spring Boot启动阶段的准备工作

3.1.1Web容器和DispatcherServlet的自动配置

Spring Boot 提供了许多自动配置类来简化开发,以下是与Web请求处理相关的重要类:

  • DispatcherServletAutoConfiguration:完成DispatcherServlet的注册和初始化。
  • WebMvcAutoConfiguration:为Spring MVC提供默认配置。

3.1.2DispatcherServlet 的注册

  • 在Spring Boot中,DispatcherServlet是Web应用的核心处理器,它的注册由DispatcherServletAutoConfiguration完成。
  • 默认注册的名称为dispatcherServlet
  • 映射路径为 /,拦截所有 HTTP 请求。

3.1.3WebMvc 配置

WebMvcAutoConfiguration会在没有用户自定义配置时,提供一套默认的Spring MVC配置,包括:

  • 注册RequestMappingHandlerMapping和RequestMappingHandlerAdapter。
  • 配置默认的视图解析器、静态资源处理器等。

3.1.4内嵌 Servlet 容器的启动

Spring Boot内置了Tomcat、Jetty等Servlet容器,以下是关键步骤:

  1. 内置容器启动:Spring Boot在启动时会通过EmbeddedWebServerFactory启动内置的Tomcat。
  2. Servlet注册:DispatcherServlet被注册为内置容器中的默认Servlet,用于接收和处理所有请求。

3.2请求到达Spring Boot的Servlet容器

3.2.1HTTP 请求进入Tomcat

当用户通过浏览器发送请求http://localhost:8080/user/all:

  1. 连接到Tomcat:
    Tomcat的Http11Processor会接收请求并解析为HTTP协议对象。
  2. 请求分发:
    请求被转发到DispatcherServlet,它是由Spring MVC注册的默认Servlet。

3.3DispatcherServlet的请求分发处理

3.1DispatcherServlet 的初始化

DispatcherServlet的init()方法会在第一次接收到请求时执行,它会完成以下准备工作:

  • 加载HandlerMapping(请求到处理器的映射)。
  • 加载HandlerAdapter(处理器的适配器)。

3.2核心组件的加载

  • RequestMappingHandlerMapping:扫描所有标注了@RequestMapping的方法,建立URL和处理器方法的映射关系。
  • RequestMappingHandlerAdapter:负责解析方法参数,调用控制器方法,并处理返回值。

3.4请求处理的完整流程

3.4.1URL到控制器方法的映射

DispatcherServlet调用RequestMappingHandlerMapping的getHandler()方法,根据请求的URL和HTTP方法匹配到对应的 HandlerMethod(这里对应 UserController#getAllUser 方法)。

3.4.2参数解析与方法调用

DispatcherServlet将请求传递给RequestMappingHandlerAdapter:

  • 解析控制器方法的参数,例如@RequestParam或JSON请求体等。
  • 调用控制器方法 getAllUser(),获得返回值"all user"。

3.5返回值处理

3.5.1处理返回值

  • 返回值通过 HandlerMethodReturnValueHandler 处理:
    • 如果是字符串(如 "all user"),则直接写入到 HTTP 响应中。

3.6最终生成响应

DispatcherServlet 将处理结果封装为 HTTP 响应,并交给 Tomcat。
Tomcat 将响应返回给客户端,最终浏览器显示 "all user"

标签:context,Spring,request,class,Boot,response,DispatcherServlet,Servlet,揭秘
From: https://blog.csdn.net/indolentSnail/article/details/144023030

相关文章

  • SpringBoot英语听力训练系统eck91 带论文文档1万字以上,文末可获取
    题目:SpringBoot英语听力训练系统eck91进度安排:(1)2024年11月1日-2024年11月15日 确定选题,下达任务书,撰写开题报告;(2)2024年11月15日-2024年12月20日提交开题报告定稿;(3)2024年12月21日-2025年3月14日 完成选题的设计、论文大纲的撰写;(4)2025年3月15日-2025年3月21日  毕......
  • SpringBoot影视资讯管理系统7x0xg 程序+源码+数据库+调试部署+开发环境
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表系统内容:用户,影片分类,最新影片,热门影片开题报告内容一、项目背景随着影视产业的快速发展,观众对影视资讯的需求日益增长。为了更好地满足用户对影视信息获取......
  • SpringBoot疫情防控期间某村外出务工人员信息管理系统xz02k 带论文文档
    开题报告内容一、项目背景与意义在疫情防控的特殊时期,对外出务工人员进行有效管理,是保障公共卫生安全、维护社会稳定的重要措施。本项目旨在利用SpringBoot技术,为某村设计并实现一个外出务工人员信息管理系统,以实现对务工人员的健康监测、行程追踪和防疫指导等功能,为疫情防控......
  • SpringBoot银行资金账户管理系统8u0th 程序+源码+数据库+调试部署+开发环境
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表系统内容:用户,银行柜台,银行开户,银行存款,银行取款,银行转账开题报告内容一、研究背景与意义随着金融业务的日益复杂和多样化,银行资金账户管理成为银行运营中......
  • SpringBoot音乐豆瓣m577f 带论文文档1万字以上,文末可获取
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表系统内容:用户,音乐类型,热门音乐,音乐排行榜,我的歌单,音乐会员,会员充值开题报告内容一、研究背景随着互联网和数字技术的快速发展,音乐行业逐渐从传统的实体......
  • SpringBoot疫苗预约系统18p43 带论文文档1万字以上,文末可获取
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表系统内容:用户,服务类型,疫苗分类,疫苗信息,服务项目,疫苗预约,服务预约开题报告内容一、研究背景与意义随着疫苗技术的不断进步和公众健康意识的显著提升,疫苗......
  • Java:基于springboot+vue的游戏交易系统
    作者主页:IT小舟简介:Java领域优质创作者、Java项目、学习资料、技术互助文中获取源码项目介绍本系统一共管理员,用户两个角色。管理员登录进入本系统操作的功能包括对商品信息,订单投诉信息,商品评价信息,商品收藏信息,会员等级信息,商品订单信息等进行管理用户登录进入本......
  • Java:基于SpringBoot的社区医疗综合服务平台
    作者主页:IT小舟简介:Java领域优质创作者、Java项目、学习资料、技术互助文中获取源码项目介绍项目介绍本系统一共管理员,用户,医生三个角色。​本次开发的中山社区医疗综合服务平台实现了字典管理、居民健康信息管理、居民就诊管理、药物信息管理、居民医保信息管理......
  • Java:168 基于springboot+vue的游戏交易系统
    作者主页:舒克日记简介:Java领域优质创作者、Java项目、学习资料、技术互助文中获取源码项目介绍本系统一共管理员,用户两个角色。管理员登录进入本系统操作的功能包括对商品信息,订单投诉信息,商品评价信息,商品收藏信息,会员等级信息,商品订单信息等进行管理用户登录进入......
  • 毕业设计 基于Springboot的教务信息管理系统
    源码获取欢迎留言一、摘要本文旨在设计与实现一个教务信息管理系统,以解决传统纸质管理方式存在的诸多不便与繁琐。随着科技的不断发展,利用计算机技术与网络通信技术来简化与优化教务管理已成为迫切需要。本系统主要包括班级管理、打卡管理、课程管理、请假管理和授课管理等......