//1 Get handlerAdapter // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); //2 执行handlerAdapter.handle // 以UserController extends MultiActionController extends AbstractController extends WebContentGenerator为例 // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
DispatcherServlet#getHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { for (HandlerAdapter ha : this.handlerAdapters) { if (logger.isTraceEnabled()) { logger.trace("Testing handler adapter [" + ha + "]"); } // 1.1 Determine if handlerAdapter is suitable for processing the handler 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"); }
For a certain system, only one handlerAdapter is generally used (ps: whether this place can be optimized), the following takes SimpleControllerHandlerAdapter as an example
Adapter Mode-Object Adapter Mode: -Delegate Relationship
In this adapter mode, the adapter accommodates a An instance of the wrapped class. In this case, the adapter calls the physics entity of the wrapped object.
https://en.wikipedia.org/wiki/%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F
SimpleControllerHandlerAdapter#support
public boolean supports(Object handler) { // 1.1.1 Determine whether the handler is a Controller instance, and if so, return the handler return (handler instanceof Controller); }
SimpleControllerHandlerAdapter#handle
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //2.1 Call handleRequest of Controller interface-interface-oriented programming return ((Controller) handler).handleRequest(request, response); }
AbstractController#handleRequest
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { // Delegate to WebContentGenerator for checking and preparing. checkAndPrepare(request, response, this instanceof LastModified); // Execute handleRequestInternal in synchronized block if required. if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { return handleRequestInternal(request, response); } } } return handleRequestInternal(request, response); }
MultiActionController#handleRequestInternal
@Override protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { try { //Parse method parameters such as method=? String methodName = this.methodNameResolver.getHandlerMethodName(request); //According to the method name, the instance method is called by reflection return invokeNamedMethod(methodName, request, response); } catch (NoSuchRequestHandlingMethodException ex) { return handleNoSuchRequestHandlingMethod(ex, request, response); } }
MultiActionController#invokeNamedMethod
protected final ModelAndView invokeNamedMethod( String methodName, HttpServletRequest request, HttpServletResponse response) throws Exception { //Get the method execution body, handlerMethodMap is initialized in the constructor Method method = this.handlerMethodMap.get(methodName); if (method == null) { throw new NoSuchRequestHandlingMethodException(methodName, getClass()); } try { //Set the method parameters (the first two of the processing method must be request and response) Class[] paramTypes = method.getParameterTypes(); List<Object> params = new ArrayList<Object>(4); params.add(request); params.add(response); if (paramTypes.length >= 3 && paramTypes[2].equals(HttpSession.class)) { HttpSession session = request.getSession(false); if (session == null) { throw new HttpSessionRequiredException( "Pre-existing session required for handler method '" + methodName + "'"); } params.add(session); } //Set the command object property according to the request, if any -VS-model driven // If last parameter isn't of HttpSession type, it's a command. if (paramTypes.length >= 3 && !paramTypes[paramTypes.length - 1].equals(HttpSession.class)) { Object command = newCommandObject(paramTypes[paramTypes.length - 1]); params.add(command); bind(request, command); } // call the method Object returnValue = method.invoke(this.delegate, params.toArray(new Object[params.size()])); return massageReturnValueIfNecessary(returnValue); } catch (InvocationTargetException ex) { // The handler method threw an exception. return handleException(request, response, ex.getTargetException()); } catch (Exception ex) { // The binding process threw an exception. return handleException(request, response, ex); } }
The handlerMethodMap is cached during initialization.
How does springmvc set the command object according to the request?
Reference:
How to perform Spring validation in MultiActionController?
https://stackoverflow.com/questions/2744587/how-to-perform-spring-validation-in-multiactioncontroller