SpringFramework之DispatcherServlet的初始化簡析

注:SpringFramework的版本是4.3.x。java

1.DispatcherServlet的類繼承圖

               

                                                           圖1 DispatchServlet的類繼承圖web

  •     FrameworkServlet經過繼承,覆寫了HttpServlet的doXX方法,將全部的http請求都轉給processRequest(HttpServletRequest,HttpServletResponse),以後調用DispatchServlet的doService(HttpServletRequest,HttpServletResponse)方法。

2.DispatcherServlet的init(...)方法調用時序圖

    調用Servlet的init方法初始化Servlet,時序圖以下所示:spring

                     

                                                          圖2 調用Servlet的init的時序圖app

    這個init(...)是Servlet的方法,在容器container初始化Servlet時調會調用Servlet的init(...)方法。DispatcherServlet中經過init(...)來生成須要的webApplicationContext。ide

    2.1 DispatcherServlet的onRefresh方法

       圖2中步驟6中的onRefresh(...)的實如今DispatcherServlet中實現,源碼以下List-1所示,initStrategies方法中對DispatcherServlet的屬性進行了初始化。學習

List-1 DispatcherServlet的onRefresh方法中的源碼this

@Override
protected void onRefresh(ApplicationContext context) {
	initStrategies(context);
}

/**
 * Initialize the strategy objects that this servlet uses.
 * <p>May be overridden in subclasses in order to initialize further strategy objects.
 */
protected void initStrategies(ApplicationContext context) {
	initMultipartResolver(context);
	initLocaleResolver(context);
	initThemeResolver(context);
	initHandlerMappings(context);
	initHandlerAdapters(context);
	initHandlerExceptionResolvers(context);
	initRequestToViewNameTranslator(context);
	initViewResolvers(context);
	initFlashMapManager(context);
}
  •     步驟7的方法體爲空,不用管。
  •     方法initMultipartResolver、initLocaleResolver、initThemeResolver、initRequestToViewNameTranslator、initFlashMapManager的處理方式幾乎都同樣。
  •     方法initHandlerMappings、initHandlerAdapters、initHandlerExceptionResolvers的處理方式幾乎都同樣。

    2.2 DispatcherServlet的initHandlerMappings方法實現

    着重來看下方法initHandlerMappings的實現,方法中的源碼以下List-2所示spa

List-2 initHandlerMappings方法的源碼debug

private void initHandlerMappings(ApplicationContext context) {
	this.handlerMappings = null;

	if (this.detectAllHandlerMappings) {
		// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
		Map<String, HandlerMapping> matchingBeans =
				BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
		if (!matchingBeans.isEmpty()) {
			this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
			// We keep HandlerMappings in sorted order.
			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.
		}
	}
	// Ensure we have at least one HandlerMapping, by registering
	// a default HandlerMapping if no other mappings are found.
	if (this.handlerMappings == null) {
		this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
		if (logger.isDebugEnabled()) {
			logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
		}
	}
}

    對LIst-2的說明:code

  •     首先從applicationContext中取出全部的HandlerMapping,獲得的是個集合,再對集合進行排序。因此咱們能夠自定義HandlerMapping,而後註冊到applicationContext中,這樣在spring就會自動使用咱們自定義的HandlerMapping了。
  •     若是從applicationContext中獲得的HandlerMapping集合爲空,則建立默認的HandlerMapping。

    來分析getDefaultStrategies的源碼,以下List-3所示。

List-3 getDefaultStrategies的源碼

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
	String key = strategyInterface.getName();
	String value = defaultStrategies.getProperty(key);
	if (value != null) {
		String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
		List<T> strategies = new ArrayList<T>(classNames.length);
		for (String className : classNames) {
			try {
				Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
				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>();
	}
}

    defaultStrategies是DispatcherServlet的一個屬性,它的初始化以下List-4所示,

List-4 defaultStrategies的初始化源碼

private static final Properties defaultStrategies;

static {
	// Load default strategy implementations from properties file.
	// This is currently strictly internal and not meant to be customized
	// by application developers.
	try {
		ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
		defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
	}
	catch (IOException ex) {
		throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
	}
}

    DEFAULT_STRATEGIES_PATH的值是DispatcherServlet.properties,咱們來看下這個文件裏面的內容,以下圖3所示,能夠看到默認狀況下HandlerMapping定義了倆個,即BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping,因此List-3中的createDefaultStrategy方法會將BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping建立爲bean,並註冊到applicationContext中。

                

                                            圖3 文件DispatcherServlet.properties的內容

    List-3中的createDefaultStrategy(context, clazz),代碼以下List-4所示。經過ApplicationContext和Class<?>,就能夠建立bean了,這種手動建立的方式能夠學習下。

List-4 方法createDefaultStrategy的源碼

protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
	return context.getAutowireCapableBeanFactory().createBean(clazz);
}
相關文章
相關標籤/搜索