Spring 自定义参数解析

缘起

我们在使用Spring的时候,通常会直接在 Controller 的 handler(自定义的接口)中填写 HttpServletRequest, HttpServletResponse, Model, HttpSession,并且在方法中使用时对象是可以使用的。
之前我一直好奇, 这是什么原理。通过这次在学习慕课网的Java秒杀系统方案优化 高性能高并发实战 时,老师的讲解是我终于不是只会用,不知其如何实现了。

原理

Spring给我们使用者预留了一个接口 HandlerMethodArgumentResolver,通过实现这个接口, 覆盖它的 supportsParameterresolveArgument 方法, 我们就可以将自己想要的对象在方法入参处自动注入了. Spring官方的名称叫做 自定义参数解析.

在学习课程的过程中, 我们很多的方法都需要一个 MiaoshaUser 对象, 下面我们结合实际需求, 通过代码展示的方式一步一步实现这个看起来很酷的功能.

给我也整一个

第一步

首先我们编写一个 UserArgumentResolver 类, 使其实现 HandlerMethodArgumentResolver 接口. 并且通过 @Component 注解将它标记为Spring管理的Bean

/**
 * @author imyzt
 * @date 2019/3/9 16:53
 * @description 实现此方法, 将自动对方法入参包含 {@link MiaoshaUser} 的对象的进行注入
 */
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {

}

第二步

我们需要覆盖它的两个方法

/**
 * @author imyzt
 * @date 2019/3/9 16:53
 * @description 实现此方法, 将自动对方法入参包含 {@link MiaoshaUser} 的对象的进行注入
 */
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        Class <?> parameterType = parameter.getParameterType();
        return parameterType == MiaoshaUser.class;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) {
        return UserContext.getUser();
    }
}

supportsParameter()

supportsParameter() 方法中判断请求参数是否被 HandlerMethodArgumentResolver 支持, 它的判断依据非常多, 具体可以查看 org.springframework.core.MethodParameter 的源代码找到合适自己业务的匹配方法. 我这里通过 getParameterType() 方法获取了参数类型, 只要是参数类型是 MiaoshaUser.class 的就表示我编写的 UserArgumentResolver 解析类支持处理该方法入参. 下面开始下一个具体处理方法.

resolveArgument(...)

resolveArgument(...) 方法及自定义参数解析的核心处理方法. Spring通过调用该方法将参数值注入到上面 supportsParameter() 支持的方法入参上面去.
我这里的处理方法比较简单, 因为我的用户信息在上一步的拦截器中已经保存在 UserContext 用户上下文信息中. 所以只需要 getUser() 即可获取用户信息.

在这里备注一下, 我们可以通过 webRequest 获取到当前请求的Request和Response信息. 代码如下

HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);

总结

通过学习慕课上面的这个项目, 对于我这种没有接触过互联网项目的人来说, 是一个互联网开发扫盲. 里面的很多东西还是非常不错的. 在学习这个项目的过程中. 写了一些小笔记, 不在于实现, 而是一些思路. 项目地址: github