首页IT科技springmvc框架图(框架进行时——SpringMVC流程简析(一))

springmvc框架图(框架进行时——SpringMVC流程简析(一))

时间2025-04-30 23:51:45分类IT科技浏览3289
导读:基于 SpringWeb(5.3.23)的接口请求分析 前情提要...

基于 SpringWeb(5.3.23)的接口请求分析

前情提要

假定当前 Web 项目中有如下实体类和接口:

package com.example.entity; public class WebUser { private String name; private Integer age; private LocalDate birthday; private Boolean gender; // getter            、setter                、toString ... } package com.example.controller; @RestController @RequestMapping("/test") public class WebController { @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()) || (WebRequest||ServletRequest||MultipartRequest||HttpSession||PushBuilder||InputStream||Reader).class.isAssignableFrom(paramType) || (HttpMethod||Locale||TimeZone||ZoneId).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 方法即获得参数值

... ...

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
nvcpldll(nvsvc32.exe 是什么进程 nvsvc32.exe可以关闭吗) c++关键字是什么(c++常见关键字总结)