框架进行时——SpringMVC流程简析(一)(springmvc框架入门教程)

  本篇文章为你整理了框架进行时——SpringMVC流程简析(一)(springmvc框架入门教程)的详细内容,包含有springmvc框架的工作执行流程 springmvc框架入门教程 springmvc工作原理 springmvc 框架 框架进行时——SpringMVC流程简析(一),希望能帮助你了解 框架进行时——SpringMVC流程简析(一)。

   @RequestMapping("/1")

   public String test1(HttpServletRequest request, @RequestParam Map String, Object params, WebUser webUser) {

   System.out.println("request.getClass() = " + request.getClass());

   System.out.println("params = " + params);

   System.out.println("webUser = " + webUser);

   return UUID.randomUUID().toString();

  

 

 

  使用 Postman 发送请求测试,结果符合预期:

  
 

  下面就一些关键点进行探究分析。

  由谁来处理本次请求?——请求处理器

  SpringMVC 中定义了多种“处理器映射”HandlerMapping,用来根据特定的请求返回对应的处理器(handler)。处理器映射的接口声明如下:

  

package org.springframework.web.servlet;

 

  public interface HandlerMapping {

   // 根据具体的请求返回一个处理器执行器链

   HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

  

 

  处理器执行器链HandlerExecutionChain由处理器和围绕该处理器的所有处理器拦截器HandlerInterceptor组成,是对处理器的一层封装(下文中“处理器”一词也代指“处理器执行器链”,如无特殊说明不再区分)。

  SpringMVC 中默认的处理器映射有以下5个:

  0 = {RequestMappingHandlerMapping@7031} (order=0)
 

  1 = {BeanNameUrlHandlerMapping@7032} (order=2)
 

  2 = {RouterFunctionMapping@7033} (order=3)
 

  3 = {SimpleUrlHandlerMapping@7034} (order=2147483646)
 

  4 = {WelcomePageHandlerMapping@7035} (order=2147483647)

  当 DispatcherServlet 被初始化时,如果处理器映射有多个,DispatcherServlet 会调用

  

// We keep HandlerMappings in sorted order.

 

  AnnotationAwareOrderComparator.sort(this.handlerMappings);

  

 

  对它们进行排序。其中的排序规则如下:

  实现了PriorityOrdered接口的优先。

  实现了Ordered接口的优先,然后按照 getOrder() 的值从小到大排序。

  如以上条件均不满足,则排到最后。

  

// 摘自 org.springframework.core.OrderComparator

 

  private int compare(Object o1, Object o2) {

   boolean p1 = o1 instanceof PriorityOrdered;

   boolean p2 = o2 instanceof PriorityOrdered;

   if (p1 !p2) {

   return -1;

   } else if (p2 !p1) {

   return 1;

   } else {

   int i1 = this.getOrder(o1);

   int i2 = this.getOrder(o2);

   return Integer.compare(i1, i2);

  private int getOrder(Object obj) {

   if (obj != null obj instanceof Ordered) {

   return ((Ordered)obj).getOrder();

   return Ordered.LOWEST_PRECEDENCE;

  

 

  由此可见,一个处理器映射可以通过实现Ordered接口后重写 getOrder() 方法以指定自身的次序。
 

  此外,AbstractHandlerMapping类中定义了一个order属性,继承了该抽象类的子类也可调用 setOrder 方法间接地指定自身的次序。

  处理器需要由处理器适配器HandlerAdapter来执行。处理器适配器的接口声明如下:

  

package org.springframework.web.servlet;

 

  public interface HandlerAdapter {

   // 判断是否支持给定的处理器

   boolean supports(Object handler);

   // 使用给定的处理器对本次请求进行处理

   ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

  

 

  SpringMVC 中默认的处理器适配器有如下4个(同处理器映射一样,它们也会被排序):

  0 = {RequestMappingHandlerAdapter@6792}
 

  1 = {HandlerFunctionAdapter@6793}
 

  2 = {HttpRequestHandlerAdapter@6794}
 

  3 = {SimpleControllerHandlerAdapter@6795}

  常用的适配器就是第一个RequestMappingHandlerAdapter,它的支持规则很简单——处理器是HandlerMethod类型的即可。而RequestMappingHandlerMapping返回的处理器正是这一类型。

  注意到 org.springframework.web.servlet.DispatcherServlet#doDispatch 方法中有如下代码片段:

  

// Determine handler for the current request.

 

  HandlerExecutionChain mappedHandler = getHandler(processedRequest);

  // Determine handler adapter for the current request.

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

  // Actually invoke the handler.

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

  

 

  即分三步:获取处理器、获取适配器、使用适配器执行处理器。

  获取处理器,就是按照次序遍历所有的处理器映射,找到第一个非空的处理器执:

  

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

 

   if (this.handlerMappings == null) {

   return null;

   for (HandlerMapping mapping : this.handlerMappings) {

   HandlerExecutionChain handler = mapping.getHandler(request);

   if (handler != null) {

   return handler;

   return null;

  

 

  获取适配器的,就是遍历所有的适配器,找到第一个支持当前处理器的适配器:

  

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

  

 

  谁来为接口的请求参数赋值?——参数解析器

  在案例中,接口可直接使用定义的三个参数 request、params 和 webUser,但并没有显示地为它们赋值——这是由 SpringMVC 的参数解析器自动完成的。

  SpringMVC 中定义了多种参数解析器HandlerMethodArgumentResolver,特定的解析器支持在特定的条件下为参数赋值。参数解析器的接口声明如下:

  

package org.springframework.web.method.support;

 

  public interface HandlerMethodArgumentResolver {

   // 是否支持这样的参数,即当参数满足什么样的条件时可以为其赋值

   boolean supportsParameter(MethodParameter parameter);

   // 如何为参数赋值

   Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;

  

 

  参数解析器有一个重要的组合器实现HandlerMethodArgumentResolverComposite,用于管理其他的参数解析器,其核心代码如下:

  

package org.springframework.web.method.support;

 

  public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {

   // 管理所有的参数解析器

   private final List HandlerMethodArgumentResolver argumentResolvers = new ArrayList ();

   // 缓存后不必每次都遍历所有

   private final Map MethodParameter, HandlerMethodArgumentResolver argumentResolverCache = new ConcurrentHashMap (256);

   // 检查所管理的参数解析器,看其中是否有支持的

   @Override

   public boolean supportsParameter(MethodParameter parameter) {

   return getArgumentResolver(parameter) != null;

   // 用第一个支持此参数的解析器来处理

   @Override @Nullable

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

   // 遍历所有已注册的参数解析器,找到第一个支持这种参数的。如果未找到则返回 null

   @Nullable

   private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {

   HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);

   if (result != null) {

   return result;

   for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {

   if (resolver.supportsParameter(parameter)) {

   this.argumentResolverCache.put(parameter, resolver);

   return resolver;

   // 通常来说不可能走到这里,因为最后一个解析器 ServletModelAttributeMethodProcessor 是几乎“万能”的

  

 

  默认的参数解析器(此处的 this.argumentResolvers)有27个,它们各自对 supportsParameter 方法的实现如下(按顺序排列):

  0 = {RequestParamMethodArgumentResolver@6892}

  

/*

 

   * 满足以下三类条件中的任意一类:

   * 1. 参数标有 @RequestParam 注解、且类型不是 Map 或其子类

   * 2. 参数标有 @RequestParam 注解、且类型是 Map 或其子类、且 @RequestParam 注解的"name"或"value"属性不为空

   * 3. 参数类型是 MultipartFile 或 Part(包括它们的数组或集合)、且没有标 @RequestPart 注解

  public boolean supportsParameter0(MethodParameter parameter) {

   if (parameter.hasParameterAnnotation(RequestParam.class)) {

   if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {

   RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);

   return (requestParam != null StringUtils.hasText(requestParam.name()));

   } else {

   return true;

   } else {

   if (parameter.hasParameterAnnotation(RequestPart.class)) {

   return false;

   parameter = parameter.nestedIfOptional();

   return MultipartResolutionDelegate.isMultipartArgument(parameter);

  

 

  1 = {RequestParamMapMethodArgumentResolver@6893}

  

/*

 

   * 同时满足以下三个条件:

   * 1. 参数类型是 Map 或其子类

   * 2. 参数标有 @RequestParam 注解

   * 3. @RequestParam 注解未设置"name"或"value"属性

  public boolean supportsParameter(MethodParameter parameter) {

   RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);

   return requestParam != null Map.class.isAssignableFrom(parameter.getParameterType()) !StringUtils.hasText(requestParam.name());

  

 

  2 = {PathVariableMethodArgumentResolver@6894}

  

/*

 

   * 满足以下两类条件中的任意一类:

   * 1. 参数标有 @PathVariable 注解、且类型不是 Map 或其子类

   * 2. 参数标有 @PathVariable 注解、且类型是 Map 或其子类、且 @PathVariable 注解的"name"或"value"属性不为空

  public boolean supportsParameter(MethodParameter parameter) {

   if (!parameter.hasParameterAnnotation(PathVariable.class)) {

   return false;

   if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {

   PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class);

   return (pathVariable != null StringUtils.hasText(pathVariable.value()));

   return true;

  

 

  3 = {PathVariableMapMethodArgumentResolver@6895}

  

/*

 

   * 同时满足以下三个条件:

   * 1. 参数类型是 Map 或其子类

   * 2. 参数标有 @PathVariable 注解

   * 3. @PathVariable 注解未设置"name"或"value"属性

  public boolean supportsParameter(MethodParameter parameter) {

   PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class);

   return (pathVariable != null Map.class.isAssignableFrom(parameter.getParameterType()) !StringUtils.hasText(pathVariable.value()));

  

 

  4 = {MatrixVariableMethodArgumentResolver@6896}

  

/*

 

   * 满足以下两类条件中的任意一类:

   * 1. 参数标有 @MatrixVariable 注解、且类型不是 Map 或其子类

   * 2. 参数标有 @MatrixVariable 注解、且类型是 Map 或其子类、且 @MatrixVariable 注解的"name"或"value"属性不为空

  public boolean supportsParameter(MethodParameter parameter) {

   if (!parameter.hasParameterAnnotation(MatrixVariable.class)) {

   return false;

   if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {

   MatrixVariable matrixVariable = parameter.getParameterAnnotation(MatrixVariable.class);

   return (matrixVariable != null StringUtils.hasText(matrixVariable.name()));

   return true;

  

 

  5 = {MatrixVariableMapMethodArgumentResolver@6897}

  

/*

 

   * 同时满足以下三个条件:

   * 1. 参数类型是 Map 或其子类

   * 2. 参数标有 @MatrixVariable 注解

   * 3. @MatrixVariable 注解未设置"name"或"value"属性

  public boolean supportsParameter(MethodParameter parameter) {

   MatrixVariable matrixVariable = parameter.getParameterAnnotation(MatrixVariable.class);

   return (matrixVariable != null Map.class.isAssignableFrom(parameter.getParameterType()) !StringUtils.hasText(matrixVariable.name()));

  

 

  6 = {ServletModelAttributeMethodProcessor@6898}
 

  ModelAttributeMethodProcessor

  

// 参数标有 @ModelAttribute 注解

 

  public boolean supportsParameter(MethodParameter parameter) {

   return parameter.hasParameterAnnotation(ModelAttribute.class);

  

 

  7 = {RequestResponseBodyMethodProcessor@6899}

  

// 参数标有 @RequestBody 注解

 

  public boolean supportsParameter(MethodParameter parameter) {

   return parameter.hasParameterAnnotation(RequestBody.class);

  

 

  8 = {RequestPartMethodArgumentResolver@6900}

  

/*

 

   * 满足以下两类条件中的任意一类:

   * 1. 参数标有 @RequestPart 注解

   * 2. 参数类型是 MultipartFile 或 Part(包括它们的数组或集合)、且没有标 @RequestParam 注解

  public boolean supportsParameter(MethodParameter parameter) {

   if (parameter.hasParameterAnnotation(RequestPart.class)) {

   return true;

   if (parameter.hasParameterAnnotation(RequestParam.class)) {

   return false;

   return MultipartResolutionDelegate.isMultipartArgument(parameter.nestedIfOptional());

  

 

  9 = {RequestHeaderMethodArgumentResolver@6901}

  

/*

 

   * 同时满足以下两个条件:

   * 1. 参数标有 @RequestHeader 注解

   * 2. 参数类型不是 Map 或其子类

  public boolean supportsParameter(MethodParameter parameter) {

   return (parameter.hasParameterAnnotation(RequestHeader.class) !Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType()));

  

 

  10 = {RequestHeaderMapMethodArgumentResolver@6902}

  

/*

 

   * 同时满足以下两个条件:

   * 1. 参数标有 @RequestHeader 注解

   * 2. 参数类型是 Map 或其子类

  public boolean supportsParameter(MethodParameter parameter) {

   return (parameter.hasParameterAnnotation(RequestHeader.class) Map.class.isAssignableFrom(parameter.getParameterType()));

  

 

  11 = {ServletCookieValueMethodArgumentResolver@6903}
 

  AbstractCookieValueMethodArgumentResolver

  

// 参数标有 @CookieValue 注解

 

  public boolean supportsParameter(MethodParameter parameter) {

   return parameter.hasParameterAnnotation(CookieValue.class);

  

 

  12 = {ExpressionValueMethodArgumentResolver@6904}

  

// 参数标有 @Value 注解

 

  public boolean supportsParameter(MethodParameter parameter) {

   return parameter.hasParameterAnnotation(Value.class);

  

 

  13 = {SessionAttributeMethodArgumentResolver@6905}

  

// 参数标有 @SessionAttribute 注解

 

  public boolean supportsParameter(MethodParameter parameter) {

   return parameter.hasParameterAnnotation(SessionAttribute.class);

  

 

  14 = {RequestAttributeMethodArgumentResolver@6906}

  

// 参数标有 @RequestAttribute 注解

 

  public boolean supportsParameter(MethodParameter parameter) {

   return parameter.hasParameterAnnotation(RequestAttribute.class);

  

 

  15 = {ServletRequestMethodArgumentResolver@6907}

  

/*

 

   * 满足以下三类条件中的任意一类:

   * 1. 参数类型 Principal 或其子类,且没有标任何注解

   * 2. 参数类型是 WebRequest、ServletRequest、MultipartRequest、HttpSession、PushBuilder、InputStream 或 Reader 或它们的子类

   * 2. 参数类型是 HttpMethod、Locale、TimeZone 或 ZoneId

  public boolean supportsParameter(MethodParameter parameter) {

   Class ? paramType = parameter.getParameterType();

   return (Principal.class.isAssignableFrom(paramType) !parameter.hasParameterAnnotations())

   (WebRequestServletRequestMultipartRequestHttpSessionPushBuilderInputStreamReader).class.isAssignableFrom(paramType)

   (HttpMethodLocaleTimeZoneZoneId).class == paramType;

  

 

  16 = {ServletResponseMethodArgumentResolver@6908}

  

// 参数类型是 ServletResponse、OutputStream 或 Writer 或它们的子类

 

  public boolean supportsParameter(MethodParameter parameter) {

   return (ServletResponse OutputStream Writer).class.isAssignableFrom(parameter.getParameterType());

  

 

  17 = {HttpEntityMethodProcessor@6909}

  

// 参数类型是 HttpEntity 或 RequestEntity

 

  public boolean supportsParameter(MethodParameter parameter) {

   Class ? parameterType = parameter.getParameterType();

   return (parameterType == HttpEntity.class) (parameterType == RequestEntity.class);

  

 

  18 = {RedirectAttributesMethodArgumentResolver@6910}

  

// 参数类型是 RedirectAttributes 或其子类

 

  public boolean supportsParameter(MethodParameter parameter) {

   return RedirectAttributes.class.isAssignableFrom(parameter.getParameterType());

  

 

  19 = {ModelMethodProcessor@6911}

  

// 参数类型是 Model 或其子类

 

  public boolean supportsParameter(MethodParameter parameter) {

   return Model.class.isAssignableFrom(parameter.getParameterType());

  

 

  20 = {MapMethodProcessor@6912}

  

/*

 

   * 同时满足以下两个条件:

   * 1. 参数类型是 Map 或其子类

   * 2. 参数没有标任何注解

  public boolean supportsParameter(MethodParameter parameter) {

   return (Map.class.isAssignableFrom(parameter.getParameterType()) parameter.getParameterAnnotations().length == 0);

  

 

  21 = {ErrorsMethodArgumentResolver@6913}

  

// 参数类型是 Errors 或其子类

 

  public boolean supportsParameter(MethodParameter parameter) {

   return Errors.class.isAssignableFrom(parameter.getParameterType());

  

 

  22 = {SessionStatusMethodArgumentResolver@6914}

  

// 参数类型是 SessionStatus 或其子类

 

  public boolean supportsParameter(MethodParameter parameter) {

   return parameter.getParameterType() == SessionStatus.class;

  

 

  23 = {UriComponentsBuilderMethodArgumentResolver@6915}

  

// 参数类型是 UriComponentsBuilder 或 ServletUriComponentsBuilder

 

  public boolean supportsParameter(MethodParameter parameter) {

   Class ? parameterType = parameter.getParameterType();

   return (parameterType == UriComponentsBuilder.class) (parameterType == ServletUriComponentsBuilder.class);

  

 

  24 = {PrincipalMethodArgumentResolver@6916}

  

// 参数类型是 Principal 或其子类

 

  public boolean supportsParameter(MethodParameter parameter) {

   return Principal.class.isAssignableFrom(parameter.getParameterType());

  

 

  25 = {RequestParamMethodArgumentResolver@6917}

  

/*

 

   * 满足以下四类条件中的任意一类:

   * 1. 参数标有 @RequestParam 注解、且类型不是 Map 或其子类

   * 2. 参数标有 @RequestParam 注解、且类型是 Map 或其子类、且 @RequestParam 注解的"name"或"value"属性不为空

   * 3. 参数类型是 MultipartFile 或 Part(包括它们的数组或集合)、且没有标 @RequestPart 注解

   * 4. 参数类型不简单、且没有标 @RequestPart 注解

  public boolean supportsParameter25(MethodParameter parameter) {

   if (parameter.hasParameterAnnotation(RequestParam.class)) {

   if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {

   RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);

   return (requestParam != null StringUtils.hasText(requestParam.name()));

   } else {

   return true;

   } else {

   if (parameter.hasParameterAnnotation(RequestPart.class)) {

   return false;

   parameter = parameter.nestedIfOptional();

   if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {

   return true;

   } else {

   return BeanUtils.isSimpleProperty(parameter.getNestedParameterType());

  

 

  26 = {ServletModelAttributeMethodProcessor@6918}

  

/*

 

   * 满足以下两个条件中的任意一个:

   * 1. 参数标有 @ModelAttribute 注解

   * 2. 参数类型不简单

  public boolean supportsParameter(MethodParameter parameter) {

   return (parameter.hasParameterAnnotation(ModelAttribute.class)) (!BeanUtils.isSimpleProperty(parameter.getParameterType()));

  

 

  逐个分析可知,案例中接口的参数:

  request:其类型是 HttpServletRequest,即 Servlet 的子类,因此会被15号解析器ServletRequestMethodArgumentResolver处理。

  params:其类型是 Map,且标有未设置属性的 @RequestParam 注解,因此会被1号解析器RequestParamMapMethodArgumentResolver处理。

  webUser:该参数不是简单类型,且没有标任何注解,只能被最后一个解析器ServletModelAttributeMethodProcessor处理。
 

  接下来调用各自的 resolveArgument 方法即获得参数值
 

  ... ...

  以上就是框架进行时——SpringMVC流程简析(一)(springmvc框架入门教程)的详细内容,想要了解更多 框架进行时——SpringMVC流程简析(一)的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: