1. 程式人生 > >spring mvc主流程原始碼閱讀(剖析)

spring mvc主流程原始碼閱讀(剖析)

第一步,通過web.xml的配置可以知道,使用者訪問url第一次先走到DispatchServlet,(預設你學過基本的java的Servlet開發)

<servlet>
		<servlet-name>springServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
</servlet>

DispatchServlet類重點閱讀

//初始化HandlerMap
private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;
    if (this.detectAllHandlerMappings) {
        Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            //解析xml的 對映關係後,存放到 handlerMapping 後面會用到
            this.handlerMappings = new ArrayList(matchingBeans.values());
            OrderComparator.sort(this.handlerMappings);
        }
    } else {
        try {
            HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        } catch (NoSuchBeanDefinitionException var3) {
            ;
        }
    }

    if (this.handlerMappings == null) {
        this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("No HandlerMappings found in servlet '" + this.getServletName() + "': using default");
        }
    }

}

下圖為斷點觀察效果

從上圖看到,其實這個map就是從spring-mvc.xml檔案中讀取的不同型別的對映,標準對映、靜態資源、攔截器對映等

 

//初始化Adapters
private void initHandlerAdapters(ApplicationContext context) {
    this.handlerAdapters = null;
    if (this.detectAllHandlerAdapters) {
        Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerAdapters = new ArrayList(matchingBeans.values());
            OrderComparator.sort(this.handlerAdapters);
        }
    } else {
        try {
            HandlerAdapter ha = (HandlerAdapter)context.getBean("handlerAdapter", HandlerAdapter.class);
            this.handlerAdapters = Collections.singletonList(ha);
        } catch (NoSuchBeanDefinitionException var3) {
            ;
        }
    }

    if (this.handlerAdapters == null) {
        this.handlerAdapters = this.getDefaultStrategies(context, HandlerAdapter.class);
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("No HandlerAdapters found in servlet '" + this.getServletName() + "': using default");
        }
    }

}

 

然後,通過斷點+原始碼玩起來了,我這裡是通過一個介面測試的,

首先執行 doService方法

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    if (this.logger.isDebugEnabled()) {
        String requestUri = urlPathHelper.getRequestUri(request);
        String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
        this.logger.debug("DispatcherServlet with name '" + this.getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + requestUri + "]");
    }

    Map<String, Object> attributesSnapshot = null;
    if (WebUtils.isIncludeRequest(request)) {
        this.logger.debug("Taking snapshot of request attributes before include");
        attributesSnapshot = new HashMap();
        Enumeration attrNames = request.getAttributeNames();

        label113:
        while(true) {
            String attrName;
            do {
                if (!attrNames.hasMoreElements()) {
                    break label113;
                }

                attrName = (String)attrNames.nextElement();
            } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));

            attributesSnapshot.put(attrName, request.getAttribute(attrName));
        }
    }

    request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
    request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
    request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
    FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
    if (inputFlashMap != null) {
        request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
    }

    request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
    request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

    try {
        this.doDispatch(request, response);
    } finally {
        if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            return;
        }

        if (attributesSnapshot != null) {
            this.restoreAttributesAfterInclude(request, attributesSnapshot);
        }

    }

}

做了一些判斷和資料的初始化工作,這裡不是核心邏輯就暫時跳過了,看

doDispatch方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;//關鍵變數,注意觀察
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

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

            try {
                processedRequest = this.checkMultipart(request);
                multipartRequestParsed = processedRequest != request;
                mappedHandler = this.getHandler(processedRequest, false);//額這裡無語了點了好幾層才找到最終獲取的Handler
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    this.noHandlerFound(processedRequest, response);
                    return;
                }

                HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());//獲取對應的adaptor
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (this.logger.isDebugEnabled()) {
                        String requestUri = urlPathHelper.getRequestUri(request);
                        this.logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
                    }

                    if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }

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

                try {
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());//執行方法
                } finally {
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

                }

                this.applyDefaultViewName(request, mv);
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            } catch (Exception var28) {
                dispatchException = var28;
            }

            this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        } catch (Exception var29) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, var29);
        } catch (Error var30) {
            this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var30);
        }

    } finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            return;
        } else {
            if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }

        }
    }
}

獲取handler

handler封裝HandlerExecutionChain,從程式碼來看就是把攔截器相關資訊補充進去

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
    chain.addInterceptors(this.getAdaptedInterceptors());
    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
    Iterator i$ = this.mappedInterceptors.iterator();

    while(i$.hasNext()) {
        MappedInterceptor mappedInterceptor = (MappedInterceptor)i$.next();
        if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
            chain.addInterceptor(mappedInterceptor.getInterceptor());
        }
    }

    return chain;
}

 

從handlerMap中獲取Adaptors,

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    Iterator i$ = this.handlerMappings.iterator();

    HandlerExecutionChain handler;
    do {
        if (!i$.hasNext()) {
            return null;
        }

        HandlerMapping hm = (HandlerMapping)i$.next();
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + this.getServletName() + "'");
        }

        handler = hm.getHandler(request);
    } while(handler == null);

    return handler;
}

執行adaptor,最後利用了反射執行代理類的方法

執行後的返回檢視邏輯

private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
    modelFactory.updateModel(webRequest, mavContainer);
    if (mavContainer.isRequestHandled()) {
        return null;
    } else {
        ModelMap model = mavContainer.getModel();
        ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
        if (!mavContainer.isViewReference()) {
            mav.setView((View)mavContainer.getView());
        }

        if (model instanceof RedirectAttributes) {
            Map<String, ?> flashAttributes = ((RedirectAttributes)model).getFlashAttributes();
            HttpServletRequest request = (HttpServletRequest)webRequest.getNativeRequest(HttpServletRequest.class);
            RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
        }

        return mav;
    }
}

總結:url->dispatchServlet->doService->doDispatch->根據url,從handlerMap獲取handler,然後根據handler獲取adaptor,通過adaptor執行要執行的方法,然後返回頁面或者介面資料(返回的邏輯沒來得及細看)

在這裡即使用到了工廠模式、代理模式