【原创】遨游springmvc之DispatcherServlet
2016-07-23 15:09
375 查看
1.机制
Dispatcher是springmvc前端控制器模式的实现,它提供一个集中的请求处理机制,所有的请求都将由一个单一的处理程序处理,Dispatcher负责请求的派遣,它与spring ioc完美继承,从而可以拥有spring的所有好处。2.原理图
图2.1 原理图通过原理图我们可知我们在用springmvc一直在强调的,它是由两个容器组成,即非web层容器和web层容器,一般配置在我们的spring.xml和springmvc.xml,非web层组件一般是整个应用都共享的,如经常用到的dao层,service层等,而DispatcherServlet则初始化springmvc上下文加载的bean如Controller、HandlerMapping、HandlerAdapter等,它只加载web层的bean
3.源代码解剖
3.1 依赖关系
直接上图(实线是继承extend、虚线是实现(implement))3.2 源码解刨
在初始化web项目的时候,首先需要初始化servlet(HttpServlet),而servlet的初始化过程则转交给了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())); 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方法
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"); } }
初始化上下文
//初始化上下文,并且将之赋给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 // 1、创建该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 //2、查找已经绑定的上下文 wac = findWebApplicationContext(); } if (wac == null) { // No context instance is defined for this servlet -> create a local one //3、如果没有找到相应的上下文,并指定父亲为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. //4、刷新上下文初始化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组件,而且我们下面的许多篇章都会围绕这这些组件
/** * 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我们需要加入以下配置<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的一些属性 |
发现一个机智的导航😳
相关文章推荐
- spring mvc 的设计模式
- spring mvc初始化及其原理
- Spring web mvc DispatcherServlet (1)---配置
- DispatcherServlet在web.xml中的配置
- Spring MVC中的DispatcherServlet
- 流程整理
- Spring MVC请求处理流程及架构
- Spring MVC DispatcherServlet的启动以及初始化
- SpringMVC
- 剖析springmvc之HelloWorld
- springMVC系列源码之初始化过程——10
- springMVC系列源码之配置文件深入——11
- Hello Spring MVC
- Spring4.0.6 源码解读-DispatcherServlet
- springMVC工作原理
- SpringMVC 流程(1)-- DispatcherServlet
- DispatcherServlet初始化过程
- spring mvc 的工作原理(1)DispatcherServlet 请求处理流程
- 剖析springmvc之HelloWorld
- SpringMVC处理过程