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/**"); } }