初学 Spring MV -- DispatcherServlet

1.目前自己在做一个项目用到了 Spring MVC 第一次用所以记录一下百度百科对DispatcherServlet的解释DispatcherServlet 是前置控制.配置在web.xml文件中的.拦截匹配的请求.DispatcherServlet是前置控制器,配置在web.xml文件中的。拦截匹配的请求,Servlet拦截匹配规则要自已定义,把拦截下来的请求,依据响应的规则分发到目标Controller来处理,是配置spring MVC的第一步。简单说就是继承了HttpServlet类,他也是Spring MVC的总控器
	    <servlet-name>spring</servlet-name>
	    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	    <!-- 可以自定义servlet.xml配置文件的位置和名称,默认为WEB-INF目录下,名称为[<servlet-name>]-servlet.xml,如spring-servlet.xml-->
		<!--  <init-param>
	        <param-name>contextConfigLocation</param-name>
	        <param-value>/WEB-INF/spring-servlet.xml</param-value>  默认
	    </init-param> -->
	    
	    <!-- 设置编码格式 -->
		<init-param>
			<param-name>encoding</param-name>  
			<param-value>UTF-8</param-value>  
		</init-param> 
	</servlet>
	
	<servlet-mapping>
	    <servlet-name>spring</servlet-name>
	    <url-pattern>*.do</url-pattern>
	</servlet-mapping>


查看DispatcherServlet源代码 可以发现他继承extends FrameworkServlet 

他们的继承关系大概如下

DispatcherServlet extends abstract class FrameworkServlet extends  abstract class HttpServletBean  extends HttpServlet implements EnvironmentCapable, EnvironmentAware 

可能不是很明白.那我就一步一步来


DispatcherServlet.Java

public class DispatcherServlet extends FrameworkServlet {
	private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
	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 'DispatcherServlet.properties': " + 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

从这个properties文件看到他会加载怎么多的spring bean

一个个来说吧

1.AcceptHeaderLocaleResolver(简单说就是国际化类)

      根据浏览器Http Header中的accept-language域判定(accept-language域中一般包含了当前操作系统的语言设定,可通过        HttpServletRequest.getLocale方法获得此域的内容)。 改变Local 是不支持的,即不能调用LocaleResolver接口的 setLocale(HttpServletRequest    request, HttpServletResponse response, Locale locale); 方法设置Local.

2.FixedThemeResolver(这快我也不理解.希望有高手可以给我解答下.顺便举个列子)

   主题解析器 //初始化themeResolver bean, 默认实现FixedThemeResolver.

   我的理解就是主要处理界面的样式比如 CSS 等之类的.

3.BeanNameUrlHandlerMapping,DefaultAnnotationHandlerMapping

   初始化handlerMappings集,将用户请求映射到我们定义的Controller中

   (1).BeanNameUrlHandlerMapping默认操作影射机制。通过bean的名影射到客户端请求的url

public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {

	/**
	 * Checks name and aliases of the given bean for URLs, starting with "/".
	 */
	@Override
	protected String[] determineUrlsForHandler(String beanName) {
		List<String> urls = new ArrayList<String>();
		if (beanName.startsWith("/")) {
			urls.add(beanName);
		}
		String[] aliases = getApplicationContext().getAliases(beanName);
		for (String alias : aliases) {
			if (alias.startsWith("/")) {
				urls.add(alias);
			}
		}
		return StringUtils.toStringArray(urls);
	}

}
默认情况下,如果spring找不到url影射的话就会自动创建 BeanNameUrlHandlerMapping

    (2).DefaultAnnotationHandlerMapping

         在Spring3.2.12已经不建议使用此类了.

4.HttpRequestHandlerAdapter, SimpleControllerHandlerAdapter , AnnotationMethodHandlerAdapter

     处理请求的映射AnnotationMethodHandlerAdapter类,通过注解,把一个URL映射到Controller类的方法上

     下面是HandlerAdapter接口的实现类

      HandlerAdapter系统级的接口,它允许在不同的请求处理器和DispatcherServlet间保持低耦合性。只要HandlerAdapter经过配    置,DispatcherServlet就能与任何类型的请求处理器相互作用。

  


5.HandlerExceptionResolver(异常处理类)



FrameworkServlet.Java

public abstract class FrameworkServlet extends HttpServletBean {

	/**
	 * Suffix for WebApplicationContext namespaces. If a servlet of this class is
	 * given the name "test" in a context, the namespace used by the servlet will
	 * resolve to "test-servlet".
	 */
	public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";

HttpServletBean.Java

public abstract class HttpServletBean extends HttpServlet
		implements EnvironmentCapable, EnvironmentAware {


DispatcherServlet实现了他的父类FrameworkServlet的onRefresh

/**
	 * This implementation calls {@link #initStrategies}.
	 */
	@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.
	 */
       //初始化默认的Spring Web MVC框架使用的策略(
	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}




简述DispatcherServlet的运行流程:

1.首先会加载初始化配置文件.该配置文件已经在上面贴出了.

     (DispatcherServlet.properties  主要包括
                                                                 LocaleResolver(本地化解析器,AcceptHeaderLocaleResolver)
                                                                 ThemeResolver(主题解析器,FixedThemeResolver)
                                                                 HandlerMapping(处理器映射,BeanNameUrlHandlerMapping)
                                                                 HandlerAdapter(控制适配器,多个)
                                                                 ViewResolver(视图解析器,InternalResourceViewResolver)
                                                                 RequestToViewNameTranslator(请求到视图名的翻译器,DefaultRequestToViewNameTranslator)

  )

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 'DispatcherServlet.properties': " + ex.getMessage());
		}
	}

2. 因为DispatcherServlet继承了FrameworkServlet 而FrameworkServlet 有继承了HttpServletBean , HttpServletBean 则最终继承了 HttpServlet


而因为HttpServletBean继承了HttpServlet 有重写了int()方法

HttpServletBean.init()源码


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()));
			//为当前的HttpServletBean初始化BeanWrapper对象, 并有可能包含自定义Editor对象
			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.
		//在所有的bean属性被设定后调用, 创建了servlet的WebApplicationContext对象
		//在他的子类 FrameworkServlet 重写了 initServletBean
		initServletBean();

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

FrameworkServlet 的initServletBean源码

/**
	 * Overridden method of {@link HttpServletBean}, invoked after any bean properties
	 * have been set. Creates this servlet's WebApplicationContext.
	 */
	@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 {
		        //WebApplicationContext继承自ApplicationContext
			this.webApplicationContext = initWebApplicationContext();//在此方法里调用了onRefresh
			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");
		}
	}









FrameworkServlet
.initWebApplicationContext源码

	/**
	 * Initialize and publish the WebApplicationContext for this servlet.
	 * <p>Delegates to {@link #createWebApplicationContext} for actual creation
	 * of the context. Can be overridden in subclasses.
	 * @return the WebApplicationContext instance
	 * @see #FrameworkServlet(WebApplicationContext)
	 * @see #setContextClass
	 * @see #setContextConfigLocation
	 */
	protected WebApplicationContext initWebApplicationContext() {
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		if (this.webApplicationContext != null) {
			// A context instance was injected at construction time -> use it
			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
			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.
			//触发refresh事件, 会调用DispatcherServlet的onRefresh方法
			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.onRefresh源码
	@Override
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}


DispatcherServlet. initStrategies源码


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

大概就这样一个流程



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值