SpringMvc最核心的類就是前端控制器DispatchServlet,作為一個Servlet,是整個SpringMvc的入口,用於調度其他的各組件工作,如Controller、HandlerMapping、ViewResolver等,控制着整個處理用戶請求的流程,本篇首先來總結一下DispatchServlet的初始化過程,及進行具體處理請求前的預准備
作為一個Servlet的主要繼承關系:HttpServletBean -- > FrameworkServlet -- > DispatchServlet,分別分析這三個類,各自所做的工作,就基本上總結了整個DispatchServlet的初始過程
1、HttpServletBean
重寫了GenericServlet的init方法,servelt實例化時init方法會被調用:
@Override
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
//將Servlet的初始化參數(initParam)保存在PropertyValues,並檢查Servlet的初始化參數包含了所必須的參數,子類可以將在this.requiredProperties指定必須的參數
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
//BeanWrapper就是對象的包裹者,主要用於對象的屬性設置,這里的this,就是DispatchServlet
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
//ServletContext的資源加載器,使用本質上是使用ServletContext對象來獲取與當前Servlet相關的資源
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
//自定義了屬性編輯器,用於編輯被包裹對象的屬性
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
//空方法留給子類自定義初始化BeanWrapper
initBeanWrapper(bw);
//將Servlet的初始化參數設置到BeanWrapper中
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
//在FrameworkServlet中實現
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
總結:主要使用ServletConfig配置信息初始化DispatchServlet的一些屬性,如使用web.xml時配置的contextConfigLocation
2、FrameworkServlet
1)重寫initServletBean()初始化IOC容器
調用鏈:HttpServletBean.init()-->FrameworkServlet.initServletBean()
@Override
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
if (this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis();
try {
//初始化ioc容器(設置父子容器並刷新)
this.webApplicationContext = initWebApplicationContext();
//空方法,留給子類擴展
initFrameworkServlet();
}
...
}
核心方法initWebApplicationContext():
protected WebApplicationContext initWebApplicationContext() {
//根據ServletContext.getAttribute來獲取到WebApplicationContext(根容器),而獲取到的根容器是之前由ContextLoaderListener(ServletContextListener)的contextInitialized方法將根容器保存在了ServletContext
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
//this.webApplicationContext為子容器(保存SpringMVC組件),如果我們使用的是配置類的方式即繼承AbstractAnnotationConfigDispatcherServletInitializer來指定創建父子容器,那么在Servlet容器啟動的時侯webApplicationContext就被創建了
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
//將根容器設置為子容器(保存SpringMVC組件)的父容器
cwac.setParent(rootContext);
}
//配置並且刷新容器(啟動初始化容器過程),之前的父子容器只是被創建沒有調用refresh
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
//如果子容器還沒又被創建,嘗試去ServletContext中以獲取
wac = findWebApplicationContext();
}
if (wac == null) {
//如果子容器還為空,就通過web.xml配置的參數contextConfigLocation指定的Xml配置文件路徑來創建一個XmlWebApplicationContext類型的ioc子容器,設置父子容器關系,並刷新。
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
//在DispatchServlet中實現
onRefresh(wac);
}
//this.publishContext指定是否將web容器發布在ServletContext中,默認為ture
if (this.publishContext) {
String attrName = getServletContextAttributeName();
//將初始化好的ioc容器放入ServletContext中
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
FrameworkServlet的initServletBean方法主要就是初始化IOC容器,包括一個子容器(保存springmvc組件,如Controller、ViewResolver、HandlerMapping等等)和一個父容器(保存業務邏輯組件,如service,dao),
2)重寫了HttpServelt的service方法
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
//處理PATCH請求
processRequest(request, response);
}
else {
//如果不是PATCH請求,調用HttpServelt.service()
super.service(request, response);
}
}
FrameworkServlet也重寫了doGet、doPost、xxx等對應處理各類型請求的方法,最終都是調用了processRequest(request, response)來處理:
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
//獲取之前LocaleContext(主要作用是封裝請求的 Locale 信息,主要就是語言信息)默認不存在
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
//創建本次請求的localeContext
LocaleContext localeContext = buildLocaleContext(request);
//獲取之前RequestAttributes(封裝request,response)默認不存在
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
//創建本次請求的requestAttributes
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
//與異步請求相關的處理
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
//將localeContext、requestAttributes分別保存在LocaleContextHolder、RequestContextHolder中,兩者都是使用ThreadLocal與當前線程綁定
initContextHolders(request, localeContext, requestAttributes);
try {
//真正的處理請求過程在DispatchServlet中實現
doService(request, response);
}
catch (ServletException ex) {
failureCause = ex;
throw ex;
}
catch (IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
//完成請求默認移除requestAttributes和localeContext
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}
//無論請求是否成功都會發布請求處理完成事件(我們可以向容器中添加相應的事件監聽器)
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
總結:1、在Servlet初始化階段,初始化了IOC容器
2、在處理請求階段,做了一些提前的准備工作
3、DispatcherServlet
1)重寫onRefresh,初始化SpringMvc工作組件
HttpServletBean.init()-->FrameworkServlet.initServletBean()-->FrameworkServlet.initWebApplicationContext()-->DispatcherServlet.onRefresh(ApplicationContext context)
@Override
protected void onRefresh(ApplicationContext context) {
//context就是在FrameworkServlet.initWebApplicationContext()中完成初始化工作的IOC容器
initStrategies(context);
}
//完成各組件的初始化
protected void initStrategies(ApplicationContext context) {
//初始化文件上傳的處理類
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
這里我們以處理器映射器的初始化initHandlerMappings(context)為例分析,其他組件的初始化處理也類似
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
//this.detectAllHandlerMappings默認為true
if (this.detectAllHandlerMappings) {
//在容器中找到所有的HandlerMapping
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
//將所有的HandlerMapping保存在handlerMappings中
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
// 排序
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
//如果在IOC容器中沒有找到任何的HandlerMapping,獲取默認的HandlerMapping
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
getDefaultStrategies(context, HandlerMapping.class)獲取默認的組件:
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
//這的key為org.springframework.web.servlet.HandlerMapping
String key = strategyInterface.getName();
//在defaultStrategies獲取我們需要創建的組件的類型,多個的話,使用逗號隔開
String value = defaultStrategies.getProperty(key);
if (value != null) {
//使用逗號為分隔符,轉化成數組
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<T>(classNames.length);
//遍歷classNames利用反射創建對象
for (String className : classNames) {
try {
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
//創建並添加到IOC容器中
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
}
catch (ClassNotFoundException ex) {
throw new BeanInitializationException(
"Could not find DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]", ex);
}
catch (LinkageError err) {
throw new BeanInitializationException(
"Error loading DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]: problem with class file or dependent class", err);
}
}
return strategies;
}
else {
return new LinkedList<T>();
}
}
//保存了各組件接口對應的默認實現類
private static final Properties defaultStrategies;
//靜態代碼塊,用於初始化defaultStrategies
static {
try {
//private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties",創建了一個與DispatcherServlet.class處於同一包下的DispatcherServlet.properties文件的資源對象
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
//創建Properties對象,保存了組件接口的對應的默認實現類
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
DispatcherServlet.properties配置文件中指定了各組件的默認實現類的全類名:
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
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
各個SpringMvc工作組件的初始化過程為:首先從IOC容器中找對應接口類型的組件,如果沒到,就創建一個在DispatcherServlet.properties中指定的默認組件接口實現類的實例
2)重寫doService,進入核心方法doDispatch(request, response)
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
//這里與RequestDispatcher.include()相關
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
//將一些組件設置到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());
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 {
//最終調用了
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
最終進入doDispatch(request, response),作為DispatchServlet最核心方法,調度着各工作組件進行具體的請求處理。
