SpringMVC原始碼解析系列2-DispatcherServlet

hahaeee發表於2018-03-20

DispatcherServlet初始化過程

DispathcerServlet繼承關係

可以看到有幾個生命週期介面:

  1. ApplicationContextAware:儲存了spring上下文

    public interface ApplicationContextAware extends Aware {
    	//上下文初始化完成後被呼叫
    	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
    }
    #org.springframework.web.servlet.FrameworkServlet	
    //儲存SpringMVC上下文 當通過Spring裝載DispatchServlet時會被呼叫
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
    	if (this.webApplicationContext == null && applicationContext instanceof WebApplicationContext) {
    		this.webApplicationContext = (WebApplicationContext) applicationContext;
    		this.webApplicationContextInjected = true;
    	}
    }
    
    複製程式碼
  2. EnvironmentAware:儲存了環境變數物件

    public interface EnvironmentAware extends Aware {
    	//環境變數物件初始化完成後被呼叫
    	void setEnvironment(Environment environment);
    }
    #org.springframework.web.servlet.HttpServletBean
    	@Override
    	public void setEnvironment(Environment environment) {
    		Assert.isInstanceOf(ConfigurableEnvironment.class, environment, "ConfigurableEnvironment required");
    		this.environment = (ConfigurableEnvironment) environment;
    	}
    複製程式碼
  3. Servlet:Servlet生命週期

    public interface Servlet {
       //serlvet初始化
        public void init(ServletConfig config) throws ServletException;
        public ServletConfig getServletConfig();
        public void service(ServletRequest req, ServletResponse res)
                throws ServletException, IOException;
        public String getServletInfo();
      //serlvet銷燬
        public void destroy();
    }
    #org.springframework.web.servlet.HttpServletBean
    @Override
    public final void init() throws ServletException {
    	...
    	initServletBean();
    }
    @Override
    public void destroy() {
    	if (this.webApplicationContext instanceof ConfigurableApplicationContext && !this.webApplicationContextInjected) {
    		//銷燬上下文
    		((ConfigurableApplicationContext) this.webApplicationContext).close();
    	}
    }
    #org.springframework.web.servlet.FrameworkServlet
    DispatcherServlet extends FrameworkServlet 
    #org.springframework.web.servlet.FrameworkServlet
    @Override
    protected final void initServletBean() throws ServletException {
    	...
    	try {
    		this.webApplicationContext = initWebApplicationContext();
    		initFrameworkServlet();
    	}
    	...
    }
    protected WebApplicationContext initWebApplicationContext() {
    	WebApplicationContext rootContext =
    			WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    	WebApplicationContext wac = null;
    	...
    	//以spring配置方式時webApplicationContext!=null
    	if (this.webApplicationContext != null) {
    			wac = this.webApplicationContext;
    			if (wac instanceof ConfigurableWebApplicationContext) {
    				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
    						cwac.setParent(rootContext);
    				}
    			}
    		}
    	if (wac == null) {
    		//建立applicationContext
    		wac = createWebApplicationContext(rootContext);
    	}
    	...
    	return wac;
    }
    protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
    	//XmlWebApplicationContext 
    	Class<?> contextClass = getContextClass();
    	...
    	//建立applicationContext
    	ConfigurableWebApplicationContext wac =
    			(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
    	wac.setEnvironment(getEnvironment());
    	//設定parent(ContextLoadListener中建立的applicationContext)
    	wac.setParent(parent);
    	//讀取contextConfigLocation配置
    	wac.setConfigLocation(getContextConfigLocation());
    	//refresh()
    	configureAndRefreshWebApplicationContext(wac);
    	return wac;
    }
    //當SpringMVC上下初始化完成後會去裝載預設策略(HandlerMapping,HandleAdapter)
    protected void initStrategies(ApplicationContext context) {
      //獲取容器中是否有其實現 沒有則載入DispatcherServlet.properties中的預設實現
    	initMultipartResolver(context);
    	initLocaleResolver(context);
    	initThemeResolver(context);
    	initHandlerMappings(context);
    	initHandlerAdapters(context);
    	initHandlerExceptionResolvers(context);
    	initRequestToViewNameTranslator(context);
    	initViewResolvers(context);
    	initFlashMapManager(context);
    }
    複製程式碼
    org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
    org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
    org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
    	org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
    org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
    	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
    	org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
    org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
    	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
    	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
    org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
    org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
    org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
    複製程式碼

DispatcherServlet呼叫過程

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
	//將相關配置設定到request作用於中
	request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
	request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
	request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
	request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
  	...
	request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
	request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

	try {
		doDispatch(request, response);
	}
}

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	...
	try {
		ModelAndView mv = null;
		Exception dispatchException = null;
		try {
			processedRequest = checkMultipart(request);
			multipartRequestParsed = (processedRequest != request);
			//1.呼叫handlerMapping獲取handlerChain
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null || mappedHandler.getHandler() == null) {
				noHandlerFound(processedRequest, response);
				return;
			}
			// 2.獲取支援該handler解析的HandlerAdapter
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
          	//前置處理(CORS時用到)
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}
			// 3.使用HandlerAdapter完成handler處理
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
			//如果是非同步請求 直接返回 
			if (asyncManager.isConcurrentHandlingStarted()) {
				return;
			}
			applyDefaultViewName(request, mv);
          	//後置處理
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}
		catch (Exception ex) {
			dispatchException = ex;
		}
      	//4.異常處理,檢視解析,渲染返回
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
	...
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
		HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
	boolean errorView = false;
  	//如果HandlerAdapter.handler()執行異常 則進行異常處理
	if (exception != null) {
		...
          Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
      //4.1
        mv = processHandlerException(request, response, handler, exception);
        errorView = (mv != null);
	}


	if (mv != null && !mv.wasCleared()) {
      	//4.2 檢視解析 渲染返回
		render(mv, request, response);
		if (errorView) {
			WebUtils.clearErrorRequestAttributes(request);
		}
	}
}
//異常處理
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
		Object handler, Exception ex) throws Exception {
	ModelAndView exMv = null;
	for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
      	//使用異常解析器解析異常(類似HandlerAdapter引數解析,呼叫)
		exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
		if (exMv != null) {
			break;
		}
    }
  	...
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
	//國際化
	Locale locale = this.localeResolver.resolveLocale(request);
	response.setLocale(locale);
	View view;
	if (mv.isReference()) {
		//4.2.1檢視解析
		view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
		...
	}
	else {
		view = mv.getView();
	}
	....
	try {
		if (mv.getStatus() != null) {
			response.setStatus(mv.getStatus().value());
		}
      	//渲染返回
		view.render(mv.getModelInternal(), request, response);
	}
	...
}
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
		HttpServletRequest request) throws Exception {
	//檢視解析
	for (ViewResolver viewResolver : this.viewResolvers) {
		View view = viewResolver.resolveViewName(viewName, locale);
		if (view != null) {
			return view;
		}
	}
	return null;
}
複製程式碼

過程概括:

  1. 呼叫HandlerMapping得到HandlerChain(Handler+Intercept)
  2. 呼叫HandlerAdapter執行handle過程(引數解析 過程呼叫)
  3. 異常處理(過程類似HanderAdapter)
  4. 呼叫ViewResolver進行檢視解析
  5. 渲染檢視

springmvc流程
上述圖片來自網路

相關文章