spring请求拦截源码跟踪。

本来想学习一下spring的方法拦截(HandlerMethodArgumentResolver),然后根据网上的教程跑了下,没跑起来,试了好久,一怒之下调试源码想看哪里出问题了,记录一下,免得下次忘记。

方法拦截器


@Component
public class MyUserArgumentResolver implements HandlerMethodArgumentResolver{

    /**
     *  MethodParameter方法参数对象 通过它可以获取该方法参数上的一些信息 如方法参数中的注解信息等
     *  通过该方法我们如果需要对某个参数进行处理  只要此处返回true即可 如对Date类型数据处理的话
     *
     * @param methodParameter
     * @return
     */
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        System.out.println(this.getClass().getName());
        //方法上面带有@Call注解的都需要被拦截下来。
        return methodParameter.getMethodAnnotation(Call.class) != null;
    }

    /**
     * 真正用于处理参数分解的方法,返回的Object就是controller方法上的形参对象。
     * @param parameter
     * @param mavContainer
     * @param webRequest
     * @param binderFactory
     * @return
     * @throws Exception
     */
    @Override
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        System.out.println("自己的业务逻辑");
        return null;
    }

}

config配置


@Configuration
public class DevConfig implements WebMvcConfigurer {

    @Autowired
    private MyUserArgumentResolver myUserArgumentResolver;

    /**
     * 添加拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    }

    /**
     * 方法拦截
     * @param resolvers
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(myUserArgumentResolver);
    }

}

被拦截的方法

@PostMapping(value = "a")
    @Call
    public String a(User user){
        return "hello world";
    }

这样是没毛病的,下面是源码处理,从config配置 addArgumentResolvers方法打上断点,然后一步一步往下走看看。

我们的MyUserArgumentResolver被存到了RequestMappingHandlerAdapter里面,这个类里面还保存了很多其他的拦截器,比如返回值方法拦截等。

接下来我们就请求被拦截的方法,看看什么时候会从customArgumentRevolvers这个集合里面拿出我们的拦截器。

1.所有的请求都交给了DispatcherServlet总调度器,该类是一个Servlet,

2.既然是Serlvet那么,首先调用doService方法,spring主要在该方法中做了一些前置处理。主要是做了一些reqeust.setAttribute处理

3.调用本类的doDispatcher方法,在该方法中获取到上面的RequestMappingHandlerAdapter,处理拦截器。

mapperHandler是一个HanderExecutionChain类,从名字来看他就是一个链式的事件处理执行类,事实上他有很多的interceptor需要处理。

随后调用getHandlerAdapter方法,获取到RequestMappingHandlerAdapter,同时获取链式处理器到Handler作为参数传进去,那么这个Hander是什么呢?跟方法看看里面做了啥。

handler就是controller中的方法。

requestmappingHandlerAdapter对于方法总是返回true.

下面开始解析,调用requestmappingHandlerAdapter的handle方法

一路跟进去会找到一个叫invokeHandlerMethod的方法,这个方法做了很多的处理,并且最终返回一个ModelAndVIew,这个类是spring处理结果之后最终返回的类,所以在这里方法里面应该有调用我们的方法拦截。
 

一步步跟进来终于能明眼看到我们的方法拦截器了,但是等等!上面是个什么鬼!这么还有那么多东西,然后你会发现很多都是你熟悉的东西,比如下标为1的RequestParamMapMethodResolver,这个看着很眼熟,会不会和@RequestParam注解有关系的,马上搜一下源码看看。

看到这个源码,我相信大家都知道了前因后果了,原来@RequestParam也是一个方法拦截器,和我们定义的其实一模一样。还有那些@RequestBody,@CookieValue等等只要spring允许在方法上面注释的基本上都有自己对应的拦截器,你请求这些方法,spring都会遍历一遍这个拦截器,然后找自己对于的注解,只要是自己处理的注解,那么就会把方法拦截下来交给自己对应的拦截器做处理,同是返回结果。到底是不是这样呢,我们来验证一下,继续往下走。

上面巴拉巴拉一大堆,下面真正进入controller方法级别的一些处理。

在controller执行之前看到了我们的拦截器,但是我们的拦截器在太后面了,所以,如果被前面的一些方法拦截到了,也就是如果我们加了@RequestParam的话,就会被@RequestParam方法给拦截下来,处理完之后返回相应的返回值。我们自己的就不会生效。到此一次controller请求,基本都看到了spring的请求处理的大致过程。

处理完之后返回的页面结果,spring对controller的返回值也有会对应的handler,到此就不在深入。

猜你喜欢

转载自blog.csdn.net/helianus/article/details/81451517
今日推荐