SpringMVC源码(二)DispatcherServlet

当ContextLoaderListener初始化完springweb容器的时候,接下来便是springmvc初始化自己的容器。

springmvc将springweb容器作为父容器。web.xml中DispatcherServlet具体配置:

 <servlet>
    <servlet-name>springServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath*:/spring-mvc*.xml</param-value>
    </init-param>
	<!--再启动之前 -->
    <load-on-startup>1</load-on-startup>
  </servlet>

DispatcherServlet类, extends FrameworkServlet.

而FrameworkServlet  extends HttpServletBean implementsApplicationContextAware  。

            

ApplicationContextAware 主要来设置ApplicationContext中的所有bean,当一个类实现了ApplicationContextAware

那么这个类就会直接获取到spring 配置文件中所有的引用bean对象。接口实现方法:

void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

HttpServletBean  继承 HttpServlet 。在web容器启动时调用它的init()方法,其主要工作就是设置我们在web.xml中配置的

contextConfigLocation 属性(文件加载地址),然后调用initServletBean(),该方法由FrameworkServlet 覆盖。

具体代码:

public final void init() throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing servlet '" + getServletName() + "'");
		}
		// Set bean properties from init parameters.
		try {	
			//加载spring-mvc的配置文件
			PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
			//属性访问器存取Bean对象的属性,所有spring创建的Bean对象,都使用该接口存取Bean属性值
			BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
			//获取服务器信息  
			ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
			bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
			//模板方法,并没有具体实现
			initBeanWrapper(bw);
			//将初始化值放到DispatcherServlet中  
			bw.setPropertyValues(pvs, true);
		}
		catch (BeansException ex) {
			logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
			throw ex;
		}
		// 又子类FrameworkServlet 覆盖
		initServletBean();
		if (logger.isDebugEnabled()) {
			logger.debug("Servlet '" + getServletName() + "' configured successfully");
		}
	}


FrameworkServlet 继承 HttpServletBean 。是springmvc 初始化容器的核心, 通过加载springmvc配置文件具体信息

和 bean的注入 ,然后调用initServletBean()来完成容器的初始化,其核心是initWebApplicationContext()方法。

具体代码:

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();
			//提供子类扩展方法 (并没有实现)
			initFrameworkServlet();
		}
		catch (ServletException ex) {
			//省略部分代码
		}
		
	}
initWebApplicationContext()具体代码:

protected WebApplicationContext initWebApplicationContext() {
		//springweb 容器 (父容器)
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		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);
				}
			}
		}
		if (wac == null) {
			//查找已经绑定的容器
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			//没找到,则创建,拿springweb的rootContext 为父容器
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			//刷新容器 (执行一些初始化,在子类DispatcherServlet中实现)
			onRefresh(wac);
		}

		if (this.publishContext) {
			// Publish the context as a servlet context attribute.
			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;
	}

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");
		}
		//实例化容器
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
		//环境属性
		wac.setEnvironment(getEnvironment());
		//父亲 root
		wac.setParent(parent);
		//springmvc 配置文件
		wac.setConfigLocation(getContextConfigLocation());
		//各种相关配置
		configureAndRefreshWebApplicationContext(wac);

		return wac;
	}
通过FrameworkServlet 完成了springmvc 容器的初始化,并在初始化之后调用onRefresh(wac)来进行属性的初始化

通过模板方式在子类DispatcherServlet进行。

DispatcherServlet 类中具体方法:

protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}
initStrategies()具体方法:
protected void initStrategies(ApplicationContext context) {		
		initMultipartResolver(context); //文件上传解析,用来支持文件上传
		initLocaleResolver(context);//本地化解析,支持国际化 默认解析器AcceptHeaderLocaleResolver 通过解析客户端Locale信息
		initThemeResolver(context);//主题解析,动态样式支持,列如换肤
		initHandlerMappings(context);//处理器映射器,返回HandlerExecutionChain对象(一个Handler、多个HandlerInterceptor)
		initHandlerAdapters(context);//处理器适配器,将处理器进行包装,从而支持多种类型的处理器
		initHandlerExceptionResolvers(context);//处理器异常解析,将异常映射到统一的页面
		initRequestToViewNameTranslator(context);//处理器没有返回逻辑视图名等相关信息时,自动将请求URL映射为逻辑视图名;
		initViewResolvers(context);//视图解析,将逻辑视图名解析为具体视图
		initFlashMapManager(context);//链接跳转,通常为重定向
	}

调用initStrategies()里面的各种属性初始化方法,springmvc的容器初始化工作也便慢慢结束。

猜你喜欢

转载自blog.csdn.net/superpojo/article/details/72870609