SpringMvc 之处理器方法参数解析器(HandlerMethodArgumentResolver)

概述

HandlerMethodArgumentResolver 是 Spring MVC 框架中的一个关键组件,用于解析控制器(Controller)方法的参数。在 Spring MVC 中,当一个请求到达时,DispatcherServlet 会负责找到对应的处理器(即控制器中的方法)来处理这个请求。在处理之前,需要解析方法的参数,这就是HandlerMethodArgumentResolver 的作用。换句话说,它负责将请求中的信息转换成处理器方法所需的参数类型,即它允许开发者将请求参数直接映射到处理器方法的参数上,而无需手动解析请求。

从代码角度说HandlerMethodArgumentResolver是一个接口,开发者实现该接口可以实现自定义的Controller方法的参数的自动注入。

java 复制代码
public interface HandlerMethodArgumentResolver {
  
  /**
  * 对应的方法参数是否支持该处理器解析处理,只有返回true才会执行resolveArgument中的逻辑
  * @param 要检查的方法参数,MethodParameter Spring MVC中对方法参数的包装类
  * @return 如果支持该参数则返回true,否则返回false
  */
  boolean supportsParameter(MethodParameter parameter);

  /**
  * 从给定的request中解析出方法参数所需要的值,并返回
  * ModelAndViewContainer 提供了request中的model
  * WebDataBinderFactory 提供了创建WebDataBinder实例的方法(当需要绑定数据和类型转换时)
  * @param parameter 要解析的方法参数。
  * @param mavContainer 当前请求的ModelAndViewContainer
  * @param webRequest 当前请求对象request
  * @param binderFactory 创建WebDataBinder实例的工厂
  * @return 返回解析后的参数值,如果不能解析返回null
  * @throws Exception 如果解析参数值出错抛出异常
  */
  @Nullable
  Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}

HandlerMethodArgumentResolver简介

HandlerMethodArgumentResolver 是 Spring MVC 提供的一个接口,用于将 HTTP 请求中的数据解析并绑定到控制器方法的参数上。它定义了两个主要的方法:supportsParameterresolveArgumentsupportsParameter 方法用于判断当前解析器是否支持给定的方法参数,而 resolveArgument 方法则用于实际解析请求中的数据,并将其作为参数值返回。

下面是mvc处理流程:

工作流程

当 Spring MVC 接收到一个 HTTP 请求并确定要调用的控制器方法后,它会按照以下步骤使用 HandlerMethodArgumentResolver 来解析方法的参数:

1. 确定解析器

Spring MVC 会遍历所有已注册的 HandlerMethodArgumentResolver 实现,并调用每个解析器的 supportsParameter 方法来检查是否有解析器支持当前方法的参数。一旦找到支持的解析器,就会使用该解析器来解析参数。

2. 解析参数

一旦确定了合适的解析器,Spring MVC 就会调用该解析器的 resolveArgument 方法来实际解析请求中的数据。这个过程可能涉及从请求头、请求体、路径变量、查询参数等不同来源提取数据,并将其转换为方法参数所需的类型。

3. 异常处理

如果在解析过程中发生异常,解析器通常会抛出一个异常,该异常随后会被 Spring MVC 的异常处理机制捕获并处理。这允许开发者为不同的异常类型提供自定义的错误响应。

自定义解析器

除了内置解析器外,Spring MVC 还允许开发者自定义 HandlerMethodArgumentResolver 实现类,以处理特殊的参数类型或实现自定义的解析逻辑。自定义解析器需要实现 HandlerMethodArgumentResolver 接口,并重写 supportsParameterresolveArgument 方法。然后,通过注册自定义解析器到 Spring MVC 的配置中,使其能够参与到参数解析的过程中。

实现步骤

自定义HandlerMethodArgumentResolver一般包含以下步骤:

  1. 创建自定义解析器类,实现 HandlerMethodArgumentResolver 接口。

  2. 覆盖 supportsParameter(MethodParameter parameter)resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory)

    • boolean supportsParameter(MethodParameter parameter);
      这个方法用于判断当前的解析器是否支持给定的方法参数(MethodParameter)。如果支持,返回 true;否则返回 false。
      参数 parameter 表示需要解析的方法参数。
    • @Nullable Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
      这个方法用于解析处理器方法的参数,并返回解析后的结果。方法返回一个 @Nullable 注解修饰的 Object 类型的对象,表示解析后的方法参数。如果解析失败或者不适用,可以返回 null。方法可能会抛出异常 Exception,表示解析过程中出现的异常情况。
      • 参数 parameter 表示需要解析的方法参数。
      • 参数 mavContainer 是一个可空的 ModelAndViewContainer 对象,用于在解析期间存储模型和视图的相关信息。
      • 参数 webRequest 表示当前的 Web 请求对象,类型为 NativeWebRequest。
      • 参数 binderFactory 是一个可空的 WebDataBinderFactory 对象,用于创建 WebDataBinder 对象,用于数据绑定和验证

    MethodParameter 是 Spring Framework 提供的一个类,用于描述方法参数的元数据信息。它提供了丰富的方法,用于获取和操作方法参数的各种信息。

方法 描述
getParameterType() 获取方法参数的类型
getParameterIndex() 获取方法参数在方法参数列表中的索引位置
getGenericParameterType() 获取方法参数的泛型类型
getMethod() 获取包含此方法参数的方法
hasParameterAnnotation(Class<? extends Annotation> annotationType) 判断方法参数是否有指定类型的注解
getParameterAnnotations() 获取方法参数上的所有注解
getParameterName() 获取方法参数的名称(需要编译时开启 -parameters 选项)
initParameterNameDiscovery(ParameterNameDiscoverer parameterNameDiscoverer) 初始化参数名称发现器,用于在运行时获取方法参数的名称
  1. 在 Spring MVC 配置中注册自定义解析器。某个被@Configuration注解的类并且实现WebMvcConfigurer接口,在addArgumentResolvers方法中添加。
java 复制代码
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.APPLICATION_JSON);
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(myArgumentResolver());
    }

    @Bean
    public MyArgumentResolver myArgumentResolver() {
        return new MyArgumentResolver();
    }
}

常用场景

自定义HandlerMethodArgumentResolver通常在以下情况下使用:

  • 当需要解析的请求参数类型不是 Spring MVC 默认支持的。
  • 当需要在参数解析过程中添加特定的逻辑,如权限检查、数据验证等

用法方法

下面代码中,创建一个自定义解析器来解析一个自定义的注解 @CurrentUser,该注解用于将当前用户的信息注入到控制器方法的参数中。

首先,定义 @CurrentUser 注解:

java 复制代码
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUser {
}

然后,创建自定义的 HandlerMethodArgumentResolver

java 复制代码
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.stereotype.Component;

@Component
public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(CurrentUser.class) && 	
          parameter.getParameterType().equals(User.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        // 假设已经有获取当前用户的方法
        User currentUser = getCurrentUser(webRequest);
        return currentUser;
    }

    private User getCurrentUser(NativeWebRequest webRequest) {
        // 这里是你的逻辑来获取当前用户,例如从Session或Security Context中
        // 返回一个新的User实例
        return new User(); 
    }
}

然后,在Spring配置中注册这个解析器,如果使用的是Java配置,可以在配置类中添加:

java 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class MyWebMVCConfig implements WebMvcConfigurer {

    @Autowired
    private CurrentUserArgumentResolver currentUserArgumentResolver;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(currentUserArgumentResolver);
    }
}

最后,在控制器中使用这个注解:

java 复制代码
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("/user/info")
    public String getUserInfo(@CurrentUser User currentUser) {
        // 这里可以使用currentUser对象,它已经被解析器填充了
        return "User info for: " + currentUser.getName(); 
    }
}

结语

HandlerMethodArgumentResolver 是 Spring MVC 框架中用于解析请求参数的关键接口。通过内置解析器和自定义解析器,Spring MVC 提供了灵活而强大的参数解析能力,使得开发者可以轻松处理各种复杂的请求参数场景。深入理解 HandlerMethodArgumentResolver 的工作原理对于掌握 Spring MVC 框架的请求处理流程和提高开发效率具有重要意义。

相关推荐
不务专业的程序员--阿飞3 分钟前
【SQL 如何解锁递归】
java·数据库·sql
嘵奇9 分钟前
Spring Boot拦截器详解:原理、实现与应用场景
java·spring boot·后端
八股文领域大手子10 分钟前
Java死锁排查:线上救火实战指南
java·开发语言·面试
jackson凌16 分钟前
【Java学习笔记】finalize方法
java·笔记·学习
fanTuanye20 分钟前
redis 缓存穿透,缓存击穿,缓存雪崩
java·redis·缓存
神秘的t37 分钟前
Spring Web MVC————入门(2)
java·spring·mvc
开开心心就好1 小时前
高效全能PDF工具,支持OCR识别
java·前端·python·pdf·ocr·maven·jetty
冷心笑看丽美人1 小时前
Spring MVC数据绑定和响应 你了解多少?
java·spring·mvc
XQ丶YTY1 小时前
大二java第一面小厂(挂)
java·开发语言·笔记·学习·面试
一零贰肆1 小时前
深入理解SpringBoot中的SpringCache缓存技术
java·springboot·springcache·缓存技术