【spring MVC】源码分析一 DispatcherServlet

 

1. dispatcherServlet 

1.1 DispatcherServlet 介绍

 DispatcherServlet  是 HTTP 请求 的  处理器(handlers)和 控制器(controllers) 的 中央调度者,例如 web UI controller,或者是 其他的基于 Http 远程服务。调度已注册的 处理器 可以处理请求,提供方便的映射 以及 异常的处理组件。

这个 servlet 非常的灵活:

       搭配 合适的  适配器(adapter)类,可以用于几乎任何工作流,提供了以下区别于 其他 请求驱动的(request-driven)的 web mvc 框架 的 功能:

             ★ 它是基于  javaBean  配置文件 机制;

             ★dispatcherServlet 可以使用 任何的  HandlerMapping 实现类(预构建或者是作为应用的部分提供,用来控制请求到处理器(handler)对象的路由) 。默认使用以下两个实现类(见 Spring jar 包中的  DispathcerServlet.properties)

 

org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

 自定义的 HandlerMapping 对象( 实现 HandlerMapping 接口,覆盖默认的方法) 可以作为 bean 定义在 Servlet 的 应用上下文中。并且这个 bean 的名称可以自定义(因为 他们是通过 类型 来 查找的)            

             ★ 可以 使用 任何  HandlerAdapter(处理器适配器);这就允许 使用任何 处理器(handler)接口。

默认的 适配器(adapter):

org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter

spring  的

org.springframework.web.HttpRequestHandler
org.springframework.web.servlet.mvc.Controller
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

 

以上配置都会被注册,handlerAdapter  对象  可以被作为 bean 添加到   应用上下文中,重写默认的  HandlerAdapter,和  HandlerMapping 一样,HandlerAdapter 的 bean 名称可以随意;

 

 

           ★  dispatcher  的异常 处理 机制  可以 通过 HandlerExceptionResolver  指定;例如映射指定的异常到错误页。

         ★  视图 处理 机制 可以 通过 ViewResolver 的 实现类 指定,把 视图 名称 解析为 视图对象。默认的视图 解析器(resolver) 是

org.springframework.web.servlet.view.InternalResourceViewResolver

ViewResolver 对象  可以 作为 bean  添加 到  应用上下文中,重写 默认的  ViewResolver。ViewResolver 的 bean 名称 可以 随意。

 

           ★ 如果用户 并没有 提供 一个 View 对象  或者 视图名称,那么 就会使用 RequestToViewNameTranslator 对象 将当前的 请求 翻译成 视图名称

           ★  解析 multipart  请求 的调度策略  是由 以下接口的实现类 决定的

org.springframework.web.multipart.MultipartResolver

包括了 Apache Commons FileUpload 的实现类和  Servlet 3相关的实现类;一般性选择 是 FileUpload  的实现类

 

org.springframework.web.multipart.commons.CommonsMultipartResolver

MultipartResolver 的 bean 名称 是  multipartResolver;没有 配置 默认的   multipartResolver 实现类,所以需要 自己配置

 

          ★ 区域 处理机制 是由 LocaleResolver 接口 决定的,LocalResolver  bean 名称是 localResolver ,默认  配置的 解析器是

 

org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

          ★ 主题处理策略 是由 ThemeResolver 接口 决定的 ,实现了一个固定的主题(theme)以及 cookie 和 session 的存储, ThemeResolver 的 bean 名称 为 themeResolver , 默认配置的 是

 

org.springframework.web.servlet.theme.FixedThemeResolver

一个 web 应用  可以 定义 任意多个  DispatcherServlet ,每个  Servlet 只在自己的 命名空间中操作,使用 映射(mapping) 和 处理器(handler)加载 自己 的 应用上下文.

仅仅当  根 应用上下文 被  ContextLoaderListener 加载时 , 这个 根 应用上下文 将会 被 所有的  DispatcherServlet 共享

 

1.2 DispatcherServlet 关系

《【spring MVC】源码分析一 DispatcherServlet》

分析:

             Aware :标记型 超类, 表明 一个 bean 需要 被 Spring 容器 的 某个 框架对象 通过 一个回调的方法 通知。 通常通过子接口 决定 ,通常是一个 无返回值并且含有一个 参数的方法。

例如 其子接口 ApplicationContextAware 接口:实现该接口的对象 是希望 感知到  运行在其中的 ApplicationContext  。进而通过 ApplicationContext 获取到已加载的 各种 bean。

ApplicationContextAware 接口源码:

public interface ApplicationContextAware extends Aware {

	
	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

 

代码示例(其他 aware 接口使用同理):

 

 

@Service
public final class SpringContext implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringContext.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public static Object getBean(String beanName) {
        return applicationContext.getBean(beanName);
    }

    public static <T>T getBean(String beanName , Class<T>clazz) {
        return applicationContext.getBean(beanName , clazz);
    }

}

 

       Servlet : Java EE 的 servlet api ,顶层父类,其中的抽象方法如下(代表了其生命周期):

 

void init(ServletConfig config); //Serlet 实例化之后由 Servlet 容器调用 ,只调用一次

ServletConfig getServletConfig(); //返回 初始化和启动参数,返回的是init 方法中传递的那个对象

void service(ServletRequest req, ServletResponse resp); // 响应请求, 通常运行在多线程的 Servlet 容器中

String getServletInfo(); //返回 servlet 的作者,版本,版权等信息

void destroy();

 

 servlet api 中提供了两种抽象实现类  GenericServelt(通用的,与协议无关的 Servlet)   以及  HttpServlet(http 协议的 Servlet),如果设置了 load-on-startup 则在 应用启动的时候调用 init 方法初始化,否则在第一次调用的时候初始化。(filter 在应用启动的时候初始化,始终在 servlet 之前初始化。listener 始终在 filter 之前初始化)

 

Spring 中的 抽象 和 实现:

HttpServletBean:将 Servlet 的 配置参数(Servlet标签中 init-param 标签的配置)置为内置的 bean属性
FrameworkServlet:Spring web框架的基础 Servlet, 和 Spring 的 ApplicationConext(应用上下文)进行了整合,该类提供了如下功能:
★  管理每个 Servlet 的 WebApplicationContext, Servlet 的配置文件是由 Servlet 命名空间中的 bean 决定的
★  无论一个请求是否成功处理都会 发布 请求处理的事件

     在 Servlet 初始化时,检测 一个叫 contextClass 的参数,如果没有声明该参数,则使用默认的 XmlWebApplicationContext.
这里注意,使用默认的 FrameworkServlet,如果使用自定义的 contextClass,则必须实现 ConfigurableWebApplicationContext:
比如 Spring 提供的基于java 代码配置的 AnnotationConfigWebApplicationContext;
     接收一个contextInitializerClasses 的初始化参数(init-param)
     接收一个 contextConfigLocation 的初始化参数(init-param)

DispatcherServlet:需要配置的 servlet

DispatcherServlet 配置案例:

 <servlet>
        <servlet-name>mybatis</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>com.ycit.config.MvcConfig</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mybatis</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

 

2. DispatcherServlet 初始化 源码流程解析(基于 spring 4.3.14)

首先从 Servlet 的 初始化方法 init开始:

Spring 中  HttpServletBean 类重写了 init 初始化方法(load-on-startup 设置则 启动时调用init 方法,否则第一次请求调用的时候调用 init 方法)。

————————HttpServletBean  init() 方法  begin——————:

        /**
	 * 将 该 servlet 的 配置参数 映射到 bean 属性上
	 * 同时 调用子类继续初始化
	 */
	@Override
	public final void init() throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing servlet '" + getServletName() + "'");
		}

		//将servlet初始化参数 设置到 bean 配置中
		PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
		if (!pvs.isEmpty()) {
			try {
	                        // 设置到 当前类 中	
                                BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
				ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
				bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
				initBeanWrapper(bw);
				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");
		}
	}

相关类说明:

 

PropertyValues:持有 一个 或者 多个  PropertyValue 对象的 容器。

——  PropertyValue: 保存 单个 bean 属性 的 信息 和 值 的 对象 ,就是一个 POJO 类。主要字段为 name  和  value 

—— ServletConfigPropertyValues: PropertyValues 在 HttpServletBean类 中的一个内部实现类,从 ServletConfig 的初始化参数 中 获取  必要信息,只包含了一个构造函数,直接父类为 MutablePropertyValues ,MutablePropertyValues 为PropertyValues 的 默认实现类。

ServletConfigPropertyValues 构造函数:

		/**
		 * 构造函数
		 * @param config 包含初始化参数的 ServletConfig
		 * @param requiredProperties 必须要配置的属性
		 */
		public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties)
				throws ServletException {

			Set<String> missingProps = (!CollectionUtils.isEmpty(requiredProperties) ?
					new HashSet<String>(requiredProperties) : null);

			Enumeration<String> paramNames = config.getInitParameterNames();//获取配置的初始化参数
			while (paramNames.hasMoreElements()) {
				String property = paramNames.nextElement();
				Object value = config.getInitParameter(property);
				addPropertyValue(new PropertyValue(property, value));//调用父类中的方法添加属性
				if (missingProps != null) {
					missingProps.remove(property);
				}
			}

			// 如果必须的属性没有配置则抛出异常
			if (!CollectionUtils.isEmpty(missingProps)) {
				throw new ServletException(
						"Initialization from ServletConfig for servlet '" + config.getServletName() +
						"' failed; the following required properties were missing: " +
						StringUtils.collectionToDelimitedString(missingProps, ", "));
			}
		}

 

以上代码 主要作用是 读取 Servlet 中的 配置参数。

相关方法说明:

initServletBean 方法:由子类 FrameworkServlet 重写,完成FrameworkServlet  需要完成的任务.

  ————————————————————————initServletBean  方法begin

FrameworkServlet 类 的 initServletBean 方法:主要是初始化 web 应用上下文,并加载配置。

        @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 {
			this.webApplicationContext = initWebApplicationContext(); // 初始化 web 应用上下文
			initFrameworkServlet(); // 提供子类自定义实现的方法,类似 该 initServletBean 方法
		}
		catch (ServletException ex) {
			this.logger.error("Context initialization failed", ex);
			throw ex;
		}
		catch (RuntimeException ex) {
			this.logger.error("Context initialization failed", ex);
			throw ex;
		}

		if (this.logger.isInfoEnabled()) {
			long elapsedTime = System.currentTimeMillis() - startTime;
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
					elapsedTime + " ms");
		}
	}

initServletBean方法 中的 initWebApplicationContext 方法:

protected WebApplicationContext initWebApplicationContext() {
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext()); // 获取根应用上下文,即 ContextLoaderListener 加载的 web 应用上下文
		WebApplicationContext wac = null;

		if (this.webApplicationContext != null) { // 在构建时已注入 应用上下文实例
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
								if (cwac.getParent() == null) {
						cwac.setParent(rootContext);
					}
					configureAndRefreshWebApplicationContext(cwac); // 配置 bean 并且刷新 web 应用上下文
				}
			}
		}
		if (wac == null) {
			wac = findWebApplicationContext();// servelt 上下文中是否 注入了 web 应用上下文
		}
		if (wac == null) {
			wac = createWebApplicationContext(rootContext); // 创建一个 web 应用上下文
		}

		if (!this.refreshEventReceived) {.
			onRefresh(wac); // 刷新 web 应用上下文
		}

		if (this.publishContext) {
			//将 web 应用上下文发布到 Servlet 的 上下文中.
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
						"' as ServletContext attribute with name [" + attrName + "]");
			}
		}

		return wac;
	}

initWebApplicationContext 方法 中的 createWebApplicationContext 方法:

	protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
		Class<?> contextClass = getContextClass();
		if (this.logger.isDebugEnabled()) {
			this.logger.debug("Servlet with name '" + getServletName() +
					"' will try to create custom WebApplicationContext context of class '" +
					contextClass.getName() + "'" + ", using parent context [" + parent + "]");
		}
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException(
					"Fatal initialization error in servlet with name '" + getServletName() +
					"': custom WebApplicationContext class [" + contextClass.getName() +
					"] is not of type ConfigurableWebApplicationContext");
		}  // 实例化 web 应用上下文
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

		wac.setEnvironment(getEnvironment());
		wac.setParent(parent);
		wac.setConfigLocation(getContextConfigLocation());

		configureAndRefreshWebApplicationContext(wac); // 配置并刷新 web 应用上下文

		return wac;
  }


protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			// The application context id is still set to its original default value
			// -> assign a more useful id based on available information
			if (this.contextId != null) {
				wac.setId(this.contextId);
			}
			else {
				// Generate default id...
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
			}
		}

		wac.setServletContext(getServletContext());
		wac.setServletConfig(getServletConfig());
		wac.setNamespace(getNamespace());
		wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));//添加 监听器

		// The wac environment's #initPropertySources will be called in any case when the context
		// is refreshed; do it eagerly here to ensure servlet property sources are in place for
		// use in any post-processing or initialization that occurs below prior to #refresh
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
		}

		postProcessWebApplicationContext(wac);
		applyInitializers(wac);
		wac.refresh();  // 这里 和 ContextLoaderListener 初始化时一致
	}

相关类说明:

SourceFilteringListener:  ApplicationListener 的装饰类,用于从指定的事件源中过滤事件,然后为 匹配的 ApplicationEvent 对象 调用委托的监听器

《【spring MVC】源码分析一 DispatcherServlet》

——直接父类 GenericApplicationListener : ApplicationListener 接口的 扩展类,暴露更多的源数据,例如支持的事件类型。spring 4.2 中 替代 SmartApplicationListener . 正确处理 基于 事件的泛型。

——父类 ApplicationListener:实现了 java.util.EventListener 接口,是 基于标准的 EventListener 接口 的 观察者设计模式。jdk 中规定 所有 的 事件 监听接口 都必须继承 EventListener.EventListener 只是一个 标记型接口。

—— 监听的事件 ApplicationEvent :所有的应用事件都要继承的抽象类,父类 EventObject 是 jdk 中 所有事件 对象的根类。所有的事件 都是由 一个 对象的 引用 ,即 “source” 来 构造的,它代表了事件最初发生的对象。

ContextRefreshListener:FrameworkServlet 的内部实现类,实现了 ApplicationListener 接口,只从 Servelt 的 WebApplicationContext 中 接收 事件,然后再调用 FrameworkServlet 实例 的  onApplicationEvent 方法。

——相关的事件 ContextRefreshEvent:FrameworkServlet 的内部实现类。当 ApplicationContext 初始化 并且 刷新 时引发的事件。直接父类 ApplicationContextEvent, ApplicationContext 引发的事件。

ConfigureAndRefreshWebApplicationContext 方法中调用的 SourceFilteringListener 构造函数

	/**
	 * @param source 该监听器 过滤的事件源,仅仅处理来自该 源对象的事件,
	 * @param delegate 委托 从指定 源 调用 事件的 监听器
	 */
	public SourceFilteringListener(Object source, ApplicationListener<?> delegate) {
		this.source = source;
		this.delegate = (delegate instanceof GenericApplicationListener ?
				(GenericApplicationListener) delegate : new GenericApplicationListenerAdapter(delegate));
	}

上面使用了 适配器设计模式来适配  监听器,此时传入的 delegate 为 ContextRefreshListener,不是 GenericApplicationListener 的 子类,需要使用适配器 GenericApplicationListenerAdapter。

ConfigureAndRefreshWebApplicationContext  中调用 WebApplicationContext 的 addApplicationListener 方法:

	@Override
	public void addApplicationListener(ApplicationListener<?> listener) {
		Assert.notNull(listener, "ApplicationListener must not be null");
		if (this.applicationEventMulticaster != null) {
			this.applicationEventMulticaster.addApplicationListener(listener);
		}
		else {
			this.applicationListeners.add(listener);
		}
	}

	/** 监听器暂存 */
	private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();


	/** 增删监听器,发布事件等的帮助类 */
	private ApplicationEventMulticaster applicationEventMulticaster;

相关类说明:

ApplicationEventMulticaster:实现该接口的对象 可以管理 监听器(增加 和删除),也可以被 应用上下文 委托来 发布事件。作用类似于 观察者模式中的 Obserable .

ConfigureAndRefreshWebApplicationContext  调用 AbstractApplicationContext 的 refresh 方法:主要就是为 web 应用上下文 进行配置,在 解析 ContextLoaderListener 源码的时候,也是走的这个代码。详情参看 ContextLoaderListener 源码解析

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// 统一管理事件发布,为下面的注册监听器做准备
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// 这里会将上面添加到 applicationListener 字段的监听器
                              //注册到 ApplicationEventMulticaster 中,类似观察者中的 Observerable 的职能
				registerListeners(); 

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// 发布相关事件
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

 

refresh  方法中调用的 registerListeners 方法:将监听器 添加到 web 应用上下文的 applicationEventMulticaster 属性中管理:

 

	protected void registerListeners() {
		// 将 applicationListeners 集合 中的监听器 添加到 ApplicationEventMulticaster 的实现类中.
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let post-processors apply to them!
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		for (String listenerBeanName : listenerBeanNames) {
			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}

		// 发布 earlyApplicationEvents 中的事件
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (earlyEventsToProcess != null) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

	/**
	 * Return the list of statically specified ApplicationListeners.
	 */
	public Collection<ApplicationListener<?>> getApplicationListeners() {
		return this.applicationListeners;
	}

refresh  方法中调用的 finishRefresh 方法:把之前加入管理的事件 发布。

	protected void finishRefresh() {
		// Initialize lifecycle processor for this context.
		initLifecycleProcessor();

		// Propagate refresh to lifecycle processor first.
		getLifecycleProcessor().onRefresh();

		// 发布 事件
		publishEvent(new ContextRefreshedEvent(this));

		// Participate in LiveBeansView MBean, if active.
		LiveBeansView.registerApplicationContext(this);
	}

publishEvent 方法中最终调用  doInvokeListener 方法————————发布事件  begin:

	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			
                      // 调用 监听器的 onApplicationEvent 方法
                      listener.onApplicationEvent(event); 
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || msg.startsWith(event.getClass().getName())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				Log logger = LogFactory.getLog(getClass());
				if (logger.isDebugEnabled()) {
					logger.debug("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

doInvokeListener 方法中的 onApplicationEvent 方法:SourceFilteringListener 中的方法,SourceFilteringListener的deletgate 为  GenericApplicationListenerAdapter,因为 ContextRefreshListener  不是 GenericApplicationListener 的子类,需要采用适配器:

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event.getSource() == this.source) {
			onApplicationEventInternal(event);
		}
	}

	protected void onApplicationEventInternal(ApplicationEvent event) {
		if (this.delegate == null) {
			throw new IllegalStateException(
					"Must specify a delegate object or override the onApplicationEventInternal method");
		}
		this.delegate.onApplicationEvent(event);
	}

所以 调用 GenericApplicationListenerAdapter 的 onApplicationEvent 方法:delegate 为 ContextRefreshListener 

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		this.delegate.onApplicationEvent(event);// delegate 为 ContextRefreshListener
	}

ContextRefreshListener 的 方法:

		@Override
		public void onApplicationEvent(ContextRefreshedEvent event) {
			FrameworkServlet.this.onApplicationEvent(event);
		}

类名.this 在 java 中被 定义为 Qualified this ,一般是在内部类中使用,用来访问外层对象实例。这里用来访问 FrameworkServlet 实例。

FrameworkServlet 的 onApplicationEvent  方法:

	public void onApplicationEvent(ContextRefreshedEvent event) {
		this.refreshEventReceived = true;
		onRefresh(event.getApplicationContext());
	}


        // 由子类 DispatcherServlet 重写
	protected void onRefresh(ApplicationContext context) {
		// For subclasses: do nothing by default.
	}

DispatcherServlet 的 onRefresh 方法:初始化一些 策略对象

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

        // 初始化 策略对象
	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context); //默认不配置 multiResolver,如果使用的话需要开发者自行定义
		initLocaleResolver(context); //默认配置 AcceptHeaderLocaleResolver
		initThemeResolver(context); // 默认配置FixedThemeResolver
		initHandlerMappings(context); //默认配置2个
		initHandlerAdapters(context); //默认配置3个
		initHandlerExceptionResolvers(context); //默认配置3个
		initRequestToViewNameTranslator(context); //默认配置 DefaultRequestToViewNameTranslator
		initViewResolvers(context); // 使用默认的 InternalResourceViewResolver,但是进行了自定义。
		initFlashMapManager(context); //默认配置SessionFlashMapManager
	}

这里主要看一下  initHandlerMappings 方法:初始化 处理器映射,其他的初始化大体相似

/**
	 * 如果在 BeanFactory 中没有 定义 HandlerMapping
	 * 将会使用 默认的 BeanNameUrlHandlerMapping
	 */
	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.
			}
		}

		//没有发现配置的HandlerMapping ,使用默认的 BeanNameUrlHandlerMapping
               // 以及 DefaultAnnotationHandlerMapping
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
			}
		}
	}

 这些使用的默认的配置均在 DispatcherServlet.properties 配置文件中定义。

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

至此 ——————————事件发布结束。

initWebApplicationContext 结束 ,完成了所有需要配置 和动作。

initFrameworkServlet 方法 目前为 空方法, DispatcherServlet 没有进行 重写。

至此 —————————————————————— initServletBean 方法 结束。

DispatcherServlet 初始化结束。

DispatcherServlet 工作流程:

1、  首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;

2、  DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;

3、  DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;

4、  HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);

5、  ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;

6、  View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;

7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。

 

 

    原文作者:Spring MVC
    原文地址: https://blog.csdn.net/lihuapiao/article/details/53888167
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞