当前位置:网站首页>HandlerMethodArgumentResolver使用和原理

HandlerMethodArgumentResolver使用和原理

2020-11-07 17:19:42 Lbj虞

HandlerMethodArgumentResolver 用于将方法参数解析为参数值的策略接口,我们常说的自定义参数解析器,源码如下 

/**
 * Strategy interface for resolving method parameters into argument values in
 * the context of a given request.
 *
 * @author Arjen Poutsma
 * @since 3.1
 * @see HandlerMethodReturnValueHandler
 */
public interface HandlerMethodArgumentResolver {

   /**
    * Whether the given {@linkplain MethodParameter method parameter} is
    * supported by this resolver.
    * @param parameter the method parameter to check
    * @return {@code true} if this resolver supports the supplied parameter;
    * {@code false} otherwise 
    */
   boolean supportsParameter(MethodParameter parameter);

   /**
    * Resolves a method parameter into an argument value from a given request.
    * A {@link ModelAndViewContainer} provides access to the model for the
    * request. A {@link WebDataBinderFactory} provides a way to create
    * a {@link WebDataBinder} instance when needed for data binding and
    * type conversion purposes.
    * @param parameter the method parameter to resolve. This parameter must
    * have previously been passed to {@link #supportsParameter} which must
    * have returned {@code true}.
    * @param mavContainer the ModelAndViewContainer for the current request
    * @param webRequest the current request
    * @param binderFactory a factory for creating {@link WebDataBinder} instances
    * @return the resolved argument value, or {@code null} if not resolvable
    * @throws Exception in case of errors with the preparation of argument values
    */
   @Nullable
   Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
         NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;

}

下面是我的一个小例子,主要是通过自定义参数解析器去将分页参数,提取出来封装成实体对象

1.首先自定义一个注解

/**
 * @Author: 虞云波(18088704)
 * @Date: 2020/11/7 10:18
 * @Description:
 */
@Target(ElementType.PARAMETER)
@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomArgumentPage {
}

2.写一个自定义参数解析器实现类

import com.suning.logistics.jwms.on.base.vo.PageBean;
import org.apache.commons.lang3.StringUtils;
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 javax.servlet.http.HttpServletRequest;

/**
 * @Author: 虞云波(18088704)
 * @Date: 2020/11/7 10:14
 * @Description:
 */
public class CustomArgumentResolvers implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(CustomArgumentPage.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        String page = request.getParameter("page");
        String pageSize = request.getParameter("pageSize");
        PageBean pageBean = new PageBean();
        if (StringUtils.isNotEmpty(page)) {
            pageBean.setCurrentPage(Integer.valueOf(page).intValue());
        }
        if (StringUtils.isNotEmpty(pageSize)) {
            pageBean.setPageSize(Integer.valueOf(pageSize).intValue());
        }
        pageBean.setStartPage((pageBean.getCurrentPage()-1)*pageBean.getPageSize());
        return pageBean;
    }
}

3.将自定义解析器注入到IOC 中

@Bean
public CustomArgumentResolvers initCustomArgumentResolvers(){
    return new CustomArgumentResolvers();
}

4.将自定义的参数解析器,注入到MvcConfigure中

@Configuration
public class WebMvcCustomConfigurer implements WebMvcConfigurer {


    @Autowired
    private CustomArgumentResolvers customArgumentResolvers;

    /**
     * Add resolvers to support custom controller method argument types.
     * <p>This does not override the built-in support for resolving handler
     * method arguments. To customize the built-in support for argument
     * resolution, configure {@link RequestMappingHandlerAdapter} directly.
     *
     * @param resolvers initially an empty list
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(customArgumentResolvers);
    }
}

5.编写测试Controller 

@RequestMapping("/queryPageConfigList")
@ResponseBody
public Object getWarehouseCodeReadyonly(@CustomArgumentPage PageBean pageBean){
    return warehouseConfigService.queryPage(pageBean,null);
}

6.效果如下

下面源码分析一波,讲述一下整个流程,

1.在Springboot  AutoConfiguration 会自动注入  WebMvcAutoConfiguration

2.在WebMvcAutoConfiguration 中 静态内部类 EnableWebMvcConfiguration它继承了DelegatingWebMvcConfiguration这个类,这个很重要,中的  requestMappingHandlerAdapter方法,初始化HandlerAdapter 

super.requestMappingHandlerAdapter()

3.在父类WebMvcConfigurationSupport 中,如下图 565行代码,会给HandlerAdapter 设置自定义的参数解析器

4.进入getArgumentResolvers方法,核心方法  addArgumentResolvers

5.是个空方法???,源码跟踪是进入了其子类 DelegatingWebMvcConfiguration 这个类中

6.继续代码跟踪下一步,会到WebMvcConfigurerComposite 中addArgumentResolvers 方法,会循环WebMvcConfigurer List 调用里面的 addArgumentResolvers 至于这个this.delegates 怎么初始化的,你们可以自己研究一下

7.最终调到我们自定义的WebMvcCustomConfigurer 中,将我们自定义的参数解析器,添加到整个参数解析List中

8.将数参数解析List 设置到HandlerAdapter 中

9.调用的时候,整个调用链如下图,刚兴趣的同学可以自己去分析一下

 

版权声明
本文为[Lbj虞]所创,转载请带上原文链接,感谢
https://my.oschina.net/u/3195939/blog/4707620