【原创】遨游springmvc之DispatcherServlet

1.机制

Dispatcher是springmvc前端控制器模式的实现,它提供一个集中的请求处理机制,全部的请求都将由一个单一的处理程序处理,Dispatcher负责请求的派遣,它与spring ioc完美继承,从而能够拥有spring的全部好处。 html

2.原理图

图2.1 原理图前端

经过原理图咱们可知咱们在用springmvc一直在强调的,它是由两个容器组成,即非web层容器和web层容器,通常配置在咱们的spring.xml和springmvc.xml,非web层组件通常是整个应用都共享的,如常常用到的dao层,service层等,而DispatcherServlet则初始化springmvc上下文加载的bean如Controller、HandlerMapping、HandlerAdapter等,它只加载web层的beanjava

3.源代码解剖

3.1 依赖关系

直接上图(实线是继承extend、虚线是实现(implement))web

3.2 源码解刨spring

在初始化web项目的时候,首先须要初始化servlet(HttpServlet),而servlet的初始化过程则转交给了HttpServletBean的init方法spring-mvc

public final void init() throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing servlet '" + getServletName() + "'");
		}

		// Set bean properties from init parameters.(给组件设置初始化参数)
		try {
			PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
			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) {
			logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
			throw ex;
		}

		// Let subclasses do whatever initialization they like.(让子类实现扩展,由FrameworkServlet实现)
		initServletBean();

		if (logger.isDebugEnabled()) {
			logger.debug("Servlet '" + getServletName() + "' configured successfully");
		}
	}

FrameworkServlet实现HttpServletBean的initServletBean方法mvc

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) {
			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");
		}
	}

初始化上下文app

//初始化上下文,而且将之赋给servlet
protected WebApplicationContext initWebApplicationContext() {
        //ROOT上下文(ContextLoaderListener加载的)
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		if (this.webApplicationContext != null) {
			// A context instance was injected at construction time -> use it
            // 一、建立该Servlet注入的上下文
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
					// The context has not yet been refreshed -> provide services such as
					// setting the parent context, setting the application context id, etc
					if (cwac.getParent() == null) {
						// The context instance was injected without an explicit parent -> set
						// the root application context (if any; may be null) as the parent
						cwac.setParent(rootContext);
					}
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		if (wac == null) {
			// No context instance was injected at construction time -> see if one
			// has been registered in the servlet context. If one exists, it is assumed
			// that the parent context (if any) has already been set and that the
			// user has performed any initialization such as setting the context id
            //二、查找已经绑定的上下文
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			// No context instance is defined for this servlet -> create a local one
            //三、若是没有找到相应的上下文,并指定父亲为ContextLoaderListener
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			// Either the context is not a ConfigurableApplicationContext with refresh
			// support or the context injected at construction time had already been
			// refreshed -> trigger initial onRefresh manually here.
            //四、刷新上下文初始化web层组件
			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;
	}

在DispatcherServlet中有一处比较核心的初始化代码:它初始化了许多核心web组件,并且咱们下面的许多篇章都会围绕这这些组件ide

/**
	 * 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);
	}

4.配置

用过springmvc web的人都知道,咱们项目中都会有一个web.xml文件,而须要启动springmvc咱们须要加入如下配置ui

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:config/spring.xml</param-value>
</context-param>


<servlet>
   <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:config/spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

load-on-startup:表示容器启动时初始化该servlet

url-pattern:表示springmvc拦截的url路径,/表示全拦截,还有好比是*.do表示拦截.do结尾的请求

DispatcherServlet能够配置本身的初始化参数

contextClass 实现WebApplicationContext接口的类,当前的servlet用它来建立上下文。若是这个参数没有指定, 默认使用XmlWebApplicationContext。
contextConfigLocation 传给上下文实例(由contextClass指定)的字符串,用来指定上下文的位置。这个字符串能够被分红多个字符串(使用逗号做为分隔符) 来支持多个上下文(在多上下文的状况下,若是同一个bean被定义两次,后面一个优先)
namespace WebApplicationContext命名空间。默认值是[server-name]-servlet
contextAttribute ServletContext的一些属性

 

发现一个机智的导航😳

相关文章
相关标签/搜索