SpringMVC 执行流程源码解析&自定义实现拦截器

1、控制器实现方式&对应的处理器适配器

不一样的实现方式调用不一样的 HandlerAdapter
  • 1.实现 Controller 接口 --> SimpleControllerHandlerAdapter
  • 2.实现 HttpRequestHandler 接口 --> HttpRequestHandlerAdapter
  • 3.经过 @Controller 注解 --> RequestMappingHandlerAdapter

2、执行流程

3、组件介绍

  • DispatcherServlet

前端控制器,用于接收请求,处理响应结果前端

  • HandlerMapping

处理器映射器,根据请求URL,找到对应的Handler。 其实就是HandlerExecutionChain ,HandlerExecutionChain 又包括了 - Handler 和 HandlerInterceptorweb

  • HandlerAdapter

处理器适配器,用于调用处理器(Handler|Controller)的方法,这是个接口,会根据不一样的接口实现调用不一样的处理器适配器。数组

  • HandlerInterceptor

处理器拦截器,自定义拦截器要实现该接口或者实现该接口的子类,根据业务实现 preHandle()、postHandle()、afterCompletion() 方法app

  • Handler

处理器Handler又名Controller,用于接收用户请求数据,调用业务方法处理请求ide

4、源码解析

从DispatcherServlet 方法开始分析,在此以前 servlet 会调用 onRefresh()、doService(),上述流程图就是从doService() --> doDispatch() 方法开始的post

/**
 * 上述流程图的核心代码,去除了源码中的其余逻辑
 */
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HttpServletRequest processedRequest = request;
   HandlerExecutionChain mappedHandler = null;

   try {
      ModelAndView mv = null;
      Exception dispatchException = null;

      try {

         // 获取处理器执行调用链 HandlerExecutionChain,包括处理器 Controller 和拦截器 HandlerInterceptor
         // Determine handler for the current request.
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
         }
        
         // 获取相应的处理器适配器,也被初始化过了
         // Determine handler adapter for the current request.
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
        
         // 调用拦截器的 preHandle()方法
         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
         }
         
         // 真正的调用Controller 中的方法,handle() 是个抽象方法,根据不一样的处理器调用
         // Actually invoke the handler.
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

         //调用拦截器的 hostHandle 方法,和调用 preHandle() 处理方式同样,就再也不分析了
         mappedHandler.applyPostHandle(processedRequest, response, mv);
      }
     
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
   }
 
}
获取处理器执行调用链对象
/**
 * this.handlerMappings 在此以前已经被初始化完成,这里直接根据 request 获取
 */
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   if (this.handlerMappings != null) {
      for (HandlerMapping mapping : this.handlerMappings) {
         HandlerExecutionChain handler = mapping.getHandler(request);
         if (handler != null) {
            return handler;
         }
      }
   }
   return null;
}
onRefresh 方法由 Servlet 调用,用来初始化处理请求用到的组件
@Override
protected void onRefresh(ApplicationContext context) {
   initStrategies(context);
}

/**
 * Initialize the strategy objects that this servlet uses.
 * <p>May be overridden in subclasses in order to initialize further strategy objects.
 */
protected void initStrategies(ApplicationContext context) {
   initMultipartResolver(context);
   initLocaleResolver(context);
   initThemeResolver(context);
   //初始化处理器执行调用链
   initHandlerMappings(context);
   //初始化处理器适配器
   initHandlerAdapters(context);
   initHandlerExceptionResolvers(context);
   initRequestToViewNameTranslator(context);
   initViewResolvers(context);
   initFlashMapManager(context);
}
调用拦截器的 preHandle()方法
/**
 * 循环遍历拦截器数组中拦截器的 preHandle()方法,true-放行,false-请求被拦截
 */
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HandlerInterceptor[] interceptors = getInterceptors();
   if (!ObjectUtils.isEmpty(interceptors)) {
      for (int i = 0; i < interceptors.length; i++) {
         HandlerInterceptor interceptor = interceptors[i];
         if (!interceptor.preHandle(request, response, this.handler)) {
            triggerAfterCompletion(request, response, null);
            return false;
         }
         this.interceptorIndex = i;
      }
   }
   return true;
}
以RequestMappingHandlerAdapter处理器适配器的 handler()方法分析
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ModelAndView mav;
	checkRequest(request);
        //...省略其余处理逻辑
            
        //真正执行 Controller 中的方法的代码,返回 ModelAndView 对象  
        mav = invokeHandlerMethod(request, response, handlerMethod);
	
	return mav;
}
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
      // 执行处理器的方法,
      //invocableMethod 就是映射过来的 Controller 类中对应的方法com.xxx.controller.XxxController#xxx()    
      invocableMethod.invokeAndHandle(webRequest, mavContainer);
      
      return getModelAndView(mavContainer, modelFactory, webRequest);
   }
   
}
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
      Object... providedArgs) throws Exception {
    
    //获取请求参数
   Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
   if (logger.isTraceEnabled()) {
      logger.trace("Arguments: " + Arrays.toString(args));
   }
   //终于要执行 Controller 的方法了
   return doInvoke(args);
}

5、自定义实现拦截器

  • 第一步:实现一个拦截器HandlerInterceptor,根据业务实现 preHandle()、postHandle()、afterCompletion() 方法
//我这只实现了 preHandle()方法,true-放行,false-请求直接返回
public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("=============执行拦截器 preHandle()================");
        return true;
    }
}
  • 第二步:把拦截器注入到 Spring 容器
/**
 * 注入的方式不少,你能够在MyInterceptor 上加@Component 注解,不用@Bean 的方式
 */
@Configuration
public class WebAppConfig implements WebMvcConfigurer {

    @Bean
    public MyInterceptor myInterceptor() {
        return new MyInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor())
                //添加拦截的 url,/**表示匹配全部,/* 表示只匹配一层
                .addPathPatterns("/**")
                //添加放行的 url
                .excludePathPatterns("/exclude/**");
    }
}
相关文章
相关标签/搜索