Initialization of HandlerAdapters

DispatcherServlet-onRefresh Initialize HandlerAdapters

/** * This implementation calls {@link #initStrategies}. */ @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); // Initialize HandlerAdapters initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }Copy the code

InitHandlerAdapters – Initialize HandlerAdapters

/** * Initialize the HandlerAdapters used by this class. * <p>If no HandlerAdapter beans are defined in the BeanFactory for this namespace, * we default to SimpleControllerHandlerAdapter. */ private void initHandlerAdapters(ApplicationContext context) { this.handlerAdapters = null; / / load all realized interface HandlerAdapter beans if (this. DetectAllHandlerAdapters) {/ / Find all HandlerAdapters in the ApplicationContext, including ancestor contexts. Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false); if (! matchingBeans.isEmpty()) { this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values()); // We keep HandlerAdapters in sorted order. AnnotationAwareOrderComparator.sort(this.handlerAdapters); }} // load only handlerAdapter else {try {handlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class); this.handlerAdapters = Collections.singletonList(ha); } catch (NoSuchBeanDefinitionException ex) { // Ignore, We 'l l add a default HandlerAdapter later.}} / / if still not found, from the DispatcherServlet. Load the default configuration properties / / Ensure we have the at further some HandlerAdapters, by registering // default HandlerAdapters if no other adapters are found. if (this.handlerAdapters == null) { this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default"); }}}Copy the code

DetectAllHandlerAdapters property – Whether all HandlerAdapters are found

1) Default to true. Load all beans that implement the HandlerAdapter interface into handlerAdapters. 2) This property can be modified using the initial parameters of the DispatcherServlet in web. XMLCopy the code
<init-param>
    <param-name>detectAllHandlerAdapters</param-name>
    <param-value>false</param-value>
</init-param>
Copy the code
DetectAllHandlerAdapters if the value of detectAllHandlerAdapters is false, only the handlerAdapter whose bean name="handlerAdapter" is loaded 3) under the condition of load is less than the DispatcherServlet will follow. The properties defined in the org. Springframework. Web. Servlet. The contents of the HandlerAdapter to load the default HandlerAdapter.Copy the code

DispatcherServlet. Properties configuration file – org. Springframework. Web. Servlet. HandlerAdapter

org.springframework.web.servlet.HandlerAdapter=
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
Copy the code

Second, request processing process

DispatcherServlet#doService calls the doDispatch method

/** * Process the actual dispatching to the handler. * <p>The handler will be obtained by applying the servlet's HandlerMappings in order. * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters * to  find the first that supports the handler class. * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers * themselves to decide which methods are acceptable. * @param request current HTTP request *  @param response current HTTP response * @throws Exception in case of any kind of processing failure */ protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest ! = request); // Determine handler for the current request. mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine the handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // If it is a GET request, if the content does not change, // Process last-Modified header, if supported by the handler. String method = request.getmethod (); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; }} // Call the interceptor in the chain of actuators, which is the loop assembled chain of actuators, to execute if (! mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.gethandler ()); if (asyncManager.isConcurrentHandlingStarted()) { return; } // If the returned ModelAndView is not null and the view is not set, set the default view. applyDefaultViewName(processedRequest, mv); // postHandle for interceptors. mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) {As of 4.3, we're processing Errors thrown from handler methods As well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } // If an exception occurs, return to the exception page. // If there is no exception, ModelAndView is not null, then the page is normally rendered. Invoke the interceptor's afterCompletion method processDispatchResult(processedRequest, Response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler ! = null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); }}}}Copy the code

In the whole doDispatch process, HandlerAdapter is involved in the following two places:

1. Get the handlerAdapter that matches the handler

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
Copy the code

The getHandlerAdapter input parameter mappedHandler:

HandlerExecutionChain mappedHandler = getHandler(processedRequest); The HandlerExecutionChain object contains one handler(such as the HandlerMethod object) and multiple HandlerInterceptor interceptor objectsCopy the code

GetHandlerAdapter source code:

/**
 * Return the HandlerAdapter for this handler object.
 * @param handler the handler object to find an adapter for
 * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
 */
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    for (HandlerAdapter ha : this.handlerAdapters) {
        if (logger.isTraceEnabled()) {
            logger.trace("Testing handler adapter [" + ha + "]");
        }
        if (ha.supports(handler)) {
            return ha;
        }
    }
    throw new ServletException("No adapter for handler [" + handler +
            "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
Copy the code

Walk through the loaded handlerAdapters(all handlerAdapters) to find a handlerAdapter that can handle the handler

Note :handlerAdapters supports a variety of handlerAdapters that implement the handlerAdapters interface to determine whether handlerAdapters can handle handlers. Different handlerAdapters handle different handlersCopy the code

2, the implementation of the handle

ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); Handle is also a method of the handlerAdapter interface and is used for handling handlerAdapter detailsCopy the code

Now that we’ve done some of the pre-loading, we can start analyzing the HandlerAdapter


Three, HandlerAdapter

HandlerAdapter functions:

In the previous step, find the corresponding Handler through the Request mapping. Then, in handlerAdapters, find a handlerAdapter that can handle the Handler type The HandlerAdapter uses the Handler to process the user's request and finally returns the ModelAndView. The HandlerAdapter is the adapter mode used to unify the interface calls of different handlersCopy the code

HandlerAdapter interface:

package org.springframework.web.servlet; Public interface HandlerAdapter {// Whether the Handler is passed in supports Boolean Supports (Object Handler); ModelAndView Handle (HttpServletRequest Request, HttpServletResponse Response, Object handler) throws Exception; Long getLastModified(HttpServletRequest Request, Object handler); }Copy the code

Fourth, the HandlerAdapter inheritance system

HandlerAdapter inheritance:

As can be seen from the diagram HandlerAdapter a total of five types of Adapter HttpRequestHandlerAdapter, SimpleServletHandlerAdapter SimpleControllerHandlerAdapter, Adapter HttpRequest respectively, the Servlet, the Controller type of Handler handle fixed type of Handler, internal call fixed method for processing AnnotationMethodHandlerAdapter marked @ Deprecated is Deprecated for adaptation annotation processor, As often use @ the realization of the Controller of this type of processor HttpRequestHandlerAdapter are very sophisticated processing by the Handler can be any method, parameters of the type and amount are not sureCopy the code

Five, HttpRequestHandlerAdapter

Adapter processor type:

@Override
public boolean supports(Object handler) {
    return (handler instanceof HttpRequestHandler);
}
Copy the code
Handles processors that implement the HttpRequestHandler interface to handle requests for static resources accessed through SpringMVCCopy the code

Processing logic:

@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, 
        HttpServletResponse response, Object handler)throws Exception {

    ((HttpRequestHandler) handler).handleRequest(request, response);

    return null;
}
Copy the code
Call HttpRequestHandler#handleRequest and return nullCopy the code

Six, SimpleServletHandlerAdapter

Adapter processor type:

@Override
public boolean supports(Object handler) {
    return (handler instanceof Servlet);
}
Copy the code
For processors that implement the Servlet interface or subclasses of servlets, you can configure servlets in web.xml, You can also configure servlets with SpringMVC. This HandlerAdapter is not used as it is loaded in handlerAdapters by defaultCopy the code

Processing logic:

@Override
public ModelAndView handle(HttpServletRequest request, 
            HttpServletResponse response, Object handler)throws Exception {

    ((Servlet) handler).service(request, response);
    return null;
}
Copy the code
Call Servlet#service to process the handlerCopy the code

Seven, SimpleControllerHandlerAdapter

Adapter processor type:

@Override
public boolean supports(Object handler) {
    return (handler instanceof Controller);
}
Copy the code
Adapter implemented Controller interface or Controller interfaces subclass of processors, such as: write the Controller inherits from MultiActionController, by SimpleControllerHandlerAdapter adaptationCopy the code

Processing logic:

@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {

    return ((Controller) handler).handleRequest(request, response);
}
Copy the code
Direct call Controller# handleRequest (specific implementation class handleRequest method) adapter SimpleUrlHandlerMapping and BeanNameUrlHandlerMapping mappingCopy the code

This section focuses on the overall flow of HandlerAdapter

From DispatchServlet#onRefresh initialization of the nine components, find the HandlerAdapter initialization load strategy, that is, register DispatcherServlet#doService call doDispatch method, See HandlerAdapter function and role in the process of the whole request processing HandlerAdapter interface definition and HandlerAdapter except RequestMappingHandlerAdapter inheritance system introduced the realization of the three kinds of adapterCopy the code

The core of the next section introduces HandlerAdapter RequestMappingHandlerAdapter