Analyse du code source SpringMVC - Analyse du code source clé


Premise points Articles Benpian utilisés pour le projet SpringMVC Bases de l'analyse du code source ------ (b) du Code

1. L'important DispatcherServlet
DispatcherServlet est la classe principale de SpringMVC, communément appelée contrôleur frontal.
Toutes les demandes du client lui seront transmises pour exécution, et enfin nous pouvons exécuter notre demande d'url (trouver la méthode de demande en fonction de l'url, et l'exécuter par réflexion)

2. Analyse du code source clé
Nous comprenons que DispatcherServlet est un contrôleur frontal, donc nos requêtes frontales passeront définitivement son traitement. Jetons un coup d'œil à la classe DispatcherServlet.
En regardant le diagramme de classes (ctrl + alt + u),
Insérez la description de l'image icivous pouvez voir que sa classe parente est FrameworkServlet et que la classe parente de FrameworkServlet est HttpServlet. En Java, l'opération de la sous-classe doit d'abord exécuter la méthode du parent, donc la méthode de HttpServlet est exécutée en premier. Voir la méthode service () de HttpServlet.

protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
    
    
        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
    
    
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
    
    
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
    
    
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
    
    
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
    
    
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
    
    
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
    
    
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
    
    
            doPut(req, resp);
            
        } else if (method.equals(METHOD_DELETE)) {
    
    
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
    
    
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
    
    
            doTrace(req,resp);
            
        } else {
    
    
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }

Ce que nous avons défini dans le projet sont toutes les méthodes GET, donc cette méthode s'exécute avec la méthode doGet (req, resp).
Insérez la description de l'image iciEntrez la méthode doGet de la sous-classe FrameworkServlet et
Insérez la description de l'image icientrez cette méthode, vous pouvez voir que
Insérez la description de l'image icice doService () est la méthode principale. Entrez et regardez (après avoir entré, nous verrons que nous sommes arrivés au contrôleur frontal, qui est DispatcherServlet)
Insérez la description de l'image ici
, puis passez à doDispatch (demande, réponse), entrez cette méthode.

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) {
    
    
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// 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;
					}
				}

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

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
    
    
					return;
				}

				applyDefaultViewName(processedRequest, mv);
				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);
			}
			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);
				}
			}
		}
	}

Maintenant, nous examinons cette méthode doDispatch (requête HttpServletRequest, réponse HttpServletResponse).

  1. processedRequest = checkMultipart(request);Déterminez s'il s'agit d'un téléchargement de fichier
  2. mappedHandler = getHandler(processedRequest);
    Entrez la méthode getHandler () à afficher.
    Insérez la description de l'image iciNous pouvons afficher le HandlerMapping dans la boucle for via le débogage.
    Insérez la description de l'image iciIl y en a cinq au total, il suffit de comprendre les deux premiers. Nous regardons principalement le premier. Vérifiez les données
    this.handlerMapping [0] data, Insérez la description de l'image icivous pouvez voir qu'il y a des intercepteurs que nous avons définis, ainsi que le mappage d'url. Pour le moment, nous savons que HandlerMapping stocke toutes les informations de mvc. Les données de this.handlerMapping [1] sont similaires, il ne recueille que les informations de configuration de démarrage xml. Et les données this.handlerMapping [0] sont les informations de configuration qui sont démarrées par la collecte des annotations.
    Après avoir vu l'
    Insérez la description de l'image icientrée,
    Insérez la description de l'image icientrez la
    Insérez la description de l'image ici
    Insérez la description de l'image icivariable lookupPath pour stocker l'url visitée.
    Nous sommes de retour à DispatcherServlet.
  3. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());寻找适配器Insérez la description de l'image iciInsérez la description de l'image iciCette méthode détermine principalement s'il s'agit d'une sous-classe de HandlerMethod, et le dernier jugement de supportsInternal ((HandlerMethod) handler) retourne true lorsque le gestionnaire instanceof HandlerMethod est true.
  4. if (!mappedHandler.applyPreHandle(processedRequest, response))
    PreHandle doit être familier. N'est-ce pas la première méthode de notre intercepteur?
    Entrez pour voir le code.
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];
				// 调用拦截器的preHandle()方法
				if (!interceptor.preHandle(request, response, this.handler)) {
    
    
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}
  1. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    Insérez la description de l'image iciInsérez la description de l'image iciIl existe plusieurs instructions importantes pour
    if (this.synchronizeOnSession)déterminer s'il faut utiliser la
    invokeHandlerMethod(request, response, handlerMethod);méthode cible d'exécution de session
  2. mappedHandler.applyPostHandle(processedRequest, response, mv);La même chose que le quatrième point, la méthode PostHandle () de l'intercepteur d'exécution, la méthode interne est la même, donc je ne la regarderai pas.
  3. processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    Entrez la méthode de visualisation. La méthode de
    Insérez la description de l'image icirender(mv, request, response);réglage de la vue de rendu
    mappedHandler.triggerAfterCompletion(request, response, null);est cliquée pour entrer dans la vue ~~ (en fait, si vous regardez ce AfterCompletion familier, vous devriez savoir ce que c'est) ~~
    Insérez la description de l'image iciIl est facile à comprendre, c'est l'appel de AfterCompletion de l'intercepteur ( ), ce qui l'explique également La question mentionnée dans les connaissances de base (2), pourquoi deux sont après l'exécution de la méthode cible. En fait, la différence entre eux est que l'un (PreHandle) est défini avant le rendu et l'autre (AfterCompletion) est défini après le rendu.

Je suppose que tu aimes

Origine blog.csdn.net/weixin_43911969/article/details/114685881
conseillé
Classement