HTTP请求拦截器是基于反射又基于动态代理来实现的?

658 阅读3分钟

前言

昨天看掘金文章的时候,看到有篇文章说,拦截器是基于反射实现的,然后又在后面加了一个括号,说:(有人说基于动态代理实现的),挺好,合这你也不清楚,不知从那里复制出来一句话,然后今天看到更恶心的一篇文章,标题是给开源引流的这种方式真恶心,介绍了某个开源,在登录时,要求给star后截图发送到邮箱,才给体验帐号,我直呼好家伙,这不是你们公众号关注这关注那,一连关注十几个最终东西也找不到在那的时候了,然后自己在发个文章说人家恶心,NB。

在说拦截器,功力不够,体会不到哪里用到了反射或者动态代理,用反射也就是Spring创建拦截器对象的时候,不能说这就是基于反射了吧?,那动态代理在拦截器中连个影子都找不到,哪里有?,源码指出啊。

拦截器在SpringMVC中是最好理解的,在创建RequestMappingHandlerMapping对象时候进行拦截器收集,RequestMappingHandlerMapping对象就负责处理我们写的Controller,Controller收集过程在他重写的afterPropertiesSet方法下,这个方法是Spring进行对象init阶段调用的。

创建RequestMappingHandlerMapping在WebMvcConfigurationSupport中,他是由@Bean方式创建的,详细可以看源码,在这个过程中,会调用子类的addInterceptors进行拦截器对象收集,这里的子类通常都是我们编写的了,到这里就熟悉了吧。

@Override
protected void addInterceptors(InterceptorRegistry registry) {
   super.addInterceptors(registry);
   registry.addInterceptor(new HandlerInterceptor(){
   });
}

而SpringMVC调用拦截器时机有三个地方,这三个时机会分别调用下面三个方法。

default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
   return true;
}

default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
      @Nullable ModelAndView modelAndView) throws Exception {
}

default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
      @Nullable Exception ex) throws Exception {
}

preHandle用来拦截,如果返回false,则进行拦截,不进入Controller,这个阶段是在DispatcherServlet中调用的,DispatcherServlet是一个Servlet,一个请求最先进入的地方,当然前面可能还有过滤器,Dispatcher意味分发,也就是DispatcherServlet负责把请求分发给对应的Controller,并且也会先调用拦截器。

进入其doDispatch方法下,可以看到下面这句代码,apply(运用)Pre(前)Handle(处理),这里就是调用拦截器中preHandle方法,

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
   return;
}

而方法也简单,就是遍历所有拦截器,只要有一个拦截器返回false,则请求终止。

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
   for (int i = 0; i < this.interceptorList.size(); i++) {
      HandlerInterceptor interceptor = this.interceptorList.get(i);
      if (!interceptor.preHandle(request, response, this.handler)) {
         triggerAfterCompletion(request, response, null);
         return false;
      }
      this.interceptorIndex = i;
   }
   return true;
}

下一个时机在同样在DispatcherServlet中的doDispatch方法下,调用所有拦截器的postHandle方法,这个时候Controller已经调用完毕了,如果继续用response对象做输出,会被追加到原本返回的信息后面,如果你使用的模板引擎,这时候也可以更改Model中的数据或者视图名称。

mappedHandler.applyPostHandle(processedRequest, response, mv);

最后一个时机在processDispatchResult方法下,调用afterCompletion,这时候不能在更改Model中的数据或者视图名称,但是也可以做输出,他用来做一些资源清理,这个调用顺序和拦截顺序相反,就是先被调用preHandle的拦截器会最后才被调用afterCompletion。

这个过程哪有什么动态代理?