springMVC处理请求全过程(参数解析以及返回值处理)

27 篇文章 0 订阅
6 篇文章 0 订阅

SpringMVC全过程略写图

在这里插入图片描述

  1. 用户发送请求,经过前端控制器Dispacherservlet(Controller的核心)将url交给处理器映射器HandlerMapping处理

  2. 处理器映射器HandlerMapping处理url,返回HandlerExecutionChain(可能包含拦截器,一定包含自定义的Controller(handler))

  3. 前端控制器将Controller交给处理器适配器HandlerAdapter处理,处理完成后,返回MV对象(ModelAndView

  4. 前端控制器将MV交给视图解析器处理ViewResolver,处理的过程:将MV拆分成Model和view两个对象,并且将model渲染到view视图上,并且将view返回给前端控制器。

  5. 最后,前端控制器将视图响应给用户

在这里插入图片描述

用户发送请求到DispatchServlet,请求查询Handle到处理器映射器(HandleMapping),此时返回一个处理器拦截器链到dispatchServlet之后再请求执行Handler到处理器适配器去选择相应处理器(就是Controller),处理器返回一个ModelAndView之后再转达到dispatchServlet,dispatchServlet在向视图解析器(ViewResolver)请求解析视图,之后视图解析器返回一个View对象给dispatchServlet,前端控制器在渲染视图,之后在响应给用户。

SpringMVC全过程详解

首先我们大家都知道SpringMvc是通过DispatcherServlet这个类和web.xml配置中的拦截来接管Tomcat中的请求的。所有想看所有关于控制器(打了Controller注解)的细节基本都是在DispatcherServlet这个类中,下面我们就来看看DispatcherServlet中的dodispatch方法:

	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 {
		//可以看出springMVC最先初始化的是文件上传组件
		processedRequest = checkMultipart(request);
		multipartRequestParsed = (processedRequest != request);
	
		//为request请求找到对应的处理器
(源码在下一个三级标题)
		mappedHandler = getHandler(processedRequest);
		//非空判断
		if (mappedHandler == null) {
			noHandlerFound(processedRequest, response);
			return;
		}
	
		//
很明显这是为了拿到处理器适配器了
		HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
	
		// 
获取Method,并且在下面代码就开始和Method比较了
		String method = request.getMethod();
		boolean isGet = "GET".equals(method);
		if (isGet || "HEAD".equals(method)) {
			long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
			if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
				return;
			}
		}
	
		if (!mappedHandler.applyPreHandle(processedRequest, response)) {
			return;
		}
	
		// Actually invoke the handler.
真正执行处理器适配的方法,返回ModelAndView对象了
		mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
	
		if (asyncManager.isConcurrentHandlingStarted()) {
			return;
		}
		
//是否需要解析view name ,渲染时需要。
		applyDefaultViewName(processedRequest, mv);
		//执行处理器的postHandler方法
		mappedHandler.applyPostHandle(processedRequest, response, mv);
	}
	//下一步的方法就是拿着ModelAndView去render(渲染)了,至此程序跑完,页面也出来了(这一步也有视图解析器工作流程)
	//将map和model参数保存在request中是在internResourceView的exposeModelRequestAttribute
	processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}

mappedHandler = getHandler(processedRequest)源码:

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	//此时会拿到所有的处理器映射器进行匹配
   if (this.handlerMappings != null) {
      for (HandlerMapping mapping : this.handlerMappings) {
		//通过处理器映射器去找到对应的处理器(三级标题为getHandler)
         HandlerExecutionChain handler = mapping.getHandler(request);
         if (handler != null) {
            return handler;
         }
      }
   }
   return null;
}

处理器映射器(handlerMappings):

在这里插入图片描述

getHandler(我们写的Controller其实就是Handler)

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	//通过这个方法来找到处理器,也就是Controller
   Object handler = getHandlerInternal(request);
	//很神奇spring做了两次null处理
   if (handler == null) {
      handler = getDefaultHandler();
   }
   if (handler == null) {
      return null;
   }
   // 如果是一个beanName那我就把你变成handler
   if (handler instanceof String) {
      String handlerName = (String) handler;
      handler = obtainApplicationContext().getBean(handlerName);
   }
	//这里就是上面过程略写中的处理器适配器返回处理器执行链,
   HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
	//打印日志处理
   if (logger.isTraceEnabled()) {
      logger.trace("Mapped to " + handler);
   }
   else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
      logger.debug("Mapped to " + executionChain.getHandler());
   }
	//条件说明:如果以上方法走下来,拿到的handler不是我们要的,那么SpringMVC会在以下语句中重新搞一下这个handler,把它变成我们想要的对象
   if (hasCorsConfigurationSource(handler)) {
      CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
      CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
      config = (config != null ? config.combine(handlerConfig) : handlerConfig);
      executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
   }

   return executionChain;
}

getHandlerInternal

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    /*
	* getLookupPathForRequest:
	* 首先通过getUrlPathHelper得到一个UrlPathHelper
	* 返回给定请求的映射查找路径,如果适用,则在当前Servlet映射中,否则返回Web应用程序中的映射查找路径。
	* 如果在RequestDispatcher包含中调用,则检测包含请求URL。也就是解析你写的映射路径
	* (UrlPathHelper就是专门解析路径的)
	*
	*
	*/
   String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
   //此时你可以看到lookupPath变成了"/list",并且在request的attribute属性中保存起来
   request.setAttribute(LOOKUP_PATH, lookupPath);
   //这一步就是映射器注册器尝试获取读锁,线程安全考虑
   this.mappingRegistry.acquireReadLock();
   try {
	  //这一步就是查找当前请求(list)的最佳匹配处理程序方法。如果找到多个匹配项,则选择最佳匹配项。
	  //(也就是如果找到多个匹配项那就也只要一个list.get(0)),此时拿到了HandlerMathod对象
      HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
      return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
   }
   finally {
	  //释放锁操作
      this.mappingRegistry.releaseReadLock();
   }
}

HandlerMethod对象:

通过断点可以看出,我们写的控制器以及@Requestmapping方法的所有信息,参数信息、路径信息、返回值信息都在这个类中保存

在这里插入图片描述

getHandlerExecutionChain(handler, request):返回处理器执行链

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
   HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
         (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
   //通过UrlpathHelp解析路劲
   String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
   for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
      if (interceptor instanceof MappedInterceptor) {
		//通过拦截器映射器去找到具体的拦截器
         MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
         if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
			//如果路径和拦截器相匹配,那就将他加在拦截器链中
            chain.addInterceptor(mappedInterceptor.getInterceptor());
         }
      }
      else {
         chain.addInterceptor(interceptor);
      }
   }
   return chain;
}

在这里插入图片描述

hasCorsConfigurationSource(handler):

protected boolean hasCorsConfigurationSource(Object handler) {
   return super.hasCorsConfigurationSource(handler) ||
         (handler instanceof HandlerMethod && this.mappingRegistry.getCorsConfiguration((HandlerMethod) handler) != null) ||
         handler.equals(PREFLIGHT_AMBIGUOUS_MATCH);
}
==========super.hasCorsConfigurationSource(handler)============
protected boolean hasCorsConfigurationSource(Object handler) {
	if (handler instanceof HandlerExecutionChain) {
		handler = ((HandlerExecutionChain) handler).getHandler();
	}
	return (handler instanceof CorsConfigurationSource || this.corsConfigurationSource != null);
}

getHandlerAdapter():获取处理器适配器的方法

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");
}

HandlerAdapter()处理器适配器类:

public interface HandlerAdapter {
   //是否支持这个处理器
   boolean supports(Object handler);
   //进行处理,并返回对应的ModelAndView
   @Nullable
   ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
  //拿到最后修改的Head
   long getLastModified(HttpServletRequest request, Object handler);

}

handleInternal():处理器适配器执行的具体方法

protected ModelAndView handleInternal(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ModelAndView mav;
   checkRequest(request);

   // Execute invokeHandlerMethod in synchronized block if required.
   if (this.synchronizeOnSession) {
      HttpSession session = request.getSession(false);
      if (session != null) {
         Object mutex = WebUtils.getSessionMutex(session);
         synchronized (mutex) {
            mav = invokeHandlerMethod(request, response, handlerMethod);
         }
      }
      else {
         // No HttpSession available -> no mutex necessary
         mav = invokeHandlerMethod(request, response, handlerMethod);
      }
   }
   else {
      // 我的方法在这里执行的,这里就会用到argumentResolver参数解析器以及returnValueHandler返回值处理器
      mav = invokeHandlerMethod(request, response, handlerMethod);
   }

   if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
      if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
         applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
      }
      else {
         prepareResponse(response);
      }
   }

   return mav;
}

invokeHandlerMethod():这里就是真真正正的调你写的控制器的方法了

  protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
    HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ServletWebRequest webRequest = new ServletWebRequest(request, response);
   try {
      WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
      ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

      ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
      if (this.argumentResolvers != null) {
		 //通过参数解析器去解析你在控制器写的方法参数
         invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
      }
      if (this.returnValueHandlers != null) {
         //同理,你控制器方法返回值就是通过这个解析的
         invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
      }
      invocableMethod.setDataBinderFactory(binderFactory);
      invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
		......
		//通过这个方法就可以到封装好的ModelAndView了,之后返回出去
      return getModelAndView(mavContainer, modelFactory, webRequest);
   }
   finally {
      webRequest.requestCompleted();
   }
}

ArgumentResolver(参数解析器):

你在Controller方法参数可以写多少种类型就取决于该类型是否有对应argumentResolver去解析

在这里插入图片描述

ReturnValueHandler(返回值处理器):

同理,你控制器方法返回值就是通过这个解析的

在这里插入图片描述

invokeAndHandle():在invokeHandlerMethod()方法中被调用了

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
      Object... providedArgs) throws Exception {
	//这一步走完,就会跳到你写的Controller的方法中了,这里面是通过动态代理来执行的,此时方法返回的ModelAndView也在这了
   Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
	//设置响应状态
   setResponseStatus(webRequest);

   if (returnValue == null) {
      if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
         disableContentCachingIfNecessary(webRequest);
         mavContainer.setRequestHandled(true);
         return;
      }
   }
   else if (StringUtils.hasText(getResponseStatusReason())) {
      mavContainer.setRequestHandled(true);
      return;
   }

   mavContainer.setRequestHandled(false);
   Assert.state(this.returnValueHandlers != null, "No return value handlers");
   try {
      this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
   }
   catch (Exception ex) {
      if (logger.isTraceEnabled()) {
         logger.trace(formatErrorForReturnValue(returnValue), ex);
      }
      throw ex;
   }
}

getModelAndView()

private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
      ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
	//请求处理结束之后,其他都是处理ModelAndView这个对象携带的数据
   modelFactory.updateModel(webRequest, mavContainer);
   if (mavContainer.isRequestHandled()) {
      return null;
   }
   ModelMap model = mavContainer.getModel();
   ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
   if (!mavContainer.isViewReference()) {
      mav.setView((View) mavContainer.getView());
   }
   if (model instanceof RedirectAttributes) {
      Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
      HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
      if (request != null) {
         RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
      }
   }
   return mav;
}

ModelAndView对象:

public class ModelAndViewContainer {

   private boolean ignoreDefaultModelOnRedirect = false;

   @Nullable
   private Object view;

   private final ModelMap defaultModel = new BindingAwareModelMap();

   @Nullable
   private ModelMap redirectModel;

   private boolean redirectModelScenario = false;

   @Nullable
   private HttpStatus status;

   private final Set<String> noBinding = new HashSet<>(4);

   private final Set<String> bindingDisabled = new HashSet<>(4);

   private final SessionStatus sessionStatus = new SimpleSessionStatus();

   private boolean requestHandled = false;


  
   public ModelMap getModel() {
      if (useDefaultModel()) {
         return this.defaultModel;
      }
      else {
         if (this.redirectModel == null) {
            this.redirectModel = new ModelMap();
         }
         return this.redirectModel;
      }
   }


   /**
    * 将所有属性复制到model
    */
   public ModelAndViewContainer addAllAttributes(@Nullable Map<String, ?> attributes) {
      getModel().addAllAttributes(attributes);
      return this;
   }

   /**
    * copy属性,name相同优先复制
    */
   public ModelAndViewContainer mergeAttributes(@Nullable Map<String, ?> attributes) {
      getModel().mergeAttributes(attributes);
      return this;
   }

   /**
    * 从Model中删除属性
    */
   public ModelAndViewContainer removeAttributes(@Nullable Map<String, ?> attributes) {
      if (attributes != null) {
         for (String key : attributes.keySet()) {
            getModel().remove(key);
         }
      }
      return this;
   }

   /**
    * Model是否包含给定的属性名
    */
   public boolean containsAttribute(String name) {
      return getModel().containsAttribute(name);
   }


}

在这里插入图片描述

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
SpringMVC是一个用于构建Web应用程序的Java框架。在SpringMVC中,处理请求和响应是通过使用控制器方法来实现的。控制器方法使用@RequestMapping注解来映射请求的URL,并通过方法参数来获取请求参数和响应对象。 在处理请求时,可以使用@RequestParam注解来获取请求参数的值。例如,可以在方法参数上使用@RequestParam注解来获取请求中的特定参数值。另外,也可以使用@PathVariable注解来获取URL中的路径参数。 在处理响应时,可以使用@ResponseBody注解将方法的返回值直接写入HTTP响应体中,而不是进行视图跳转。这样可以直接返回字符串、JSON格式的数据或其他类型的数据。 另外,在SpringMVC中,还有一些核心组件,如处理器映射器、处理器适配器和视图解析器。处理器映射器负责将请求映射到相应的控制器方法,处理器适配器负责将请求参数绑定到方法参数,并调用相应的控制器方法,视图解析器负责将方法的返回值解析为视图。 总结起来,SpringMVC通过控制器方法、注解和核心组件来处理请求和响应,使得开发者可以方便地构建Web应用程序。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *3* [springMVC请求和响应](https://blog.csdn.net/weixin_38088097/article/details/105840310)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [SpringMVC请求和响应](https://blog.csdn.net/weixin_51146329/article/details/123166475)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

five-five

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

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

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

打赏作者

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

抵扣说明:

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

余额充值