SpringMVC--DispatcherServlet

来源:互联网 发布:云笔记本 知乎 编辑:程序博客网 时间:2024/05/19 03:43

DispatcherServlet是前端控制器设计模式的实现。提供SpringMVC集中访问点,而且负责职责的分派,并且与Spring IOC 容器无缝集成,从而可以获得Spring所有的优点。如下图:

DispatcherServlet主要的职责是调度,本身主要用于控制流程:

1,文件上传解析

2,通过HandlerMapping,将请求映射到处理(返回一个HandlerExecutionChain,它包括一个处理器,多个HandlerInterceptor拦截器);

3,通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器)

4,通过ViewResolver解析逻辑视图名到具体视图实现

5,渲染具体视图

6,将异常讲给HandlerExceptionResolver来解析

 

DispatcherServletweb.xml中的配置

<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-servlet.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:表示哪些请求交给 Spring Web MVC处理, “/”是用来定义默认 servlet映射的。也可以如“*.html”示拦截所有以 html 为扩展名的请求。

 

有关DispatcherServlet初始化集成体系结构如下:

初始化顺序如下:

1HttpServletBean继承HttpServlet,因此在Web容器启动时将调用它的init方法,该初始化方法的主要作用

将Servlet初始化参数(init-param)设置到该组件上

提供给子类初始化扩展点,initServletBean(),该方法由FrameworkServlet 覆盖。

 

@Override

publicfinal void init() throws ServletException {

if(logger.isDebugEnabled()) {

logger.debug("Initializingservlet '" + getServletName() + "'");

}

 

//Set bean properties from init parameters.

try{

PropertyValuespvs = new ServletConfigPropertyValues(getServletConfig(),this.requiredProperties);

BeanWrapperbw = PropertyAccessorFactory.forBeanPropertyAccess(this);

ResourceLoaderresourceLoader = new ServletContextResourceLoader(getServletContext());

bw.registerCustomEditor(Resource.class,new ResourceEditor(resourceLoader, getEnvironment()));

initBeanWrapper(bw);

bw.setPropertyValues(pvs,true);

}

catch(BeansException ex) {

logger.error("Failedto set bean properties on servlet '" + getServletName() + "'",ex);

throwex;

}

 

//Let subclasses do whatever initialization they like.

//提供给子类初始化的扩展点,该方法由FrameworkServlet覆盖

initServletBean();

 

if(logger.isDebugEnabled()) {

logger.debug("Servlet'" + getServletName() + "' configured successfully");

}

}

 

2FrameworkServlet继承HttpServletBean,通过initServletBean()进行 Web 上下文初始化,该方法主要覆盖一下两件事情:

初始化web 上下文;

提供给子类初始化扩展点;

 

@Override

protectedfinal void initServletBean() throws ServletException {

getServletContext().log("InitializingSpring FrameworkServlet '" + getServletName() + "'");

if(this.logger.isInfoEnabled()) {

this.logger.info("FrameworkServlet'" + getServletName() + "': initialization started");

}

longstartTime = System.currentTimeMillis();

 

try{

//初始化Web上下文

this.webApplicationContext= initWebApplicationContext();

//提供给子类初始化扩展点

initFrameworkServlet();

}

catch(ServletException ex) {

this.logger.error("Contextinitialization failed", ex);

throwex;

}

catch(RuntimeException ex) {

this.logger.error("Contextinitialization failed", ex);

throwex;

}

 

if(this.logger.isInfoEnabled()) {

longelapsedTime = System.currentTimeMillis() - startTime;

this.logger.info("FrameworkServlet'" + getServletName() + "': initialization completed in " +

elapsedTime+ " ms");

}

}

 

protectedWebApplicationContext initWebApplicationContext() {

//ROOT上下文(ContextLoaderListener加载的)

WebApplicationContextrootContext =

WebApplicationContextUtils.getWebApplicationContext(getServletContext());

WebApplicationContextwac = null;

 

if(this.webApplicationContext != null) {

//A context instance was injected at construction time -> use it

wac= this.webApplicationContext;

if(wac instanceof ConfigurableWebApplicationContext) {

ConfigurableWebApplicationContextcwac = (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.

onRefresh(wac);

}

 

if(this.publishContext) {

//Publish the context as a servlet context attribute.

StringattrName = getServletContextAttributeName();

getServletContext().setAttribute(attrName,wac);

if(this.logger.isDebugEnabled()) {

this.logger.debug("PublishedWebApplicationContext of servlet '" + getServletName() +

"'as ServletContext attribute with name [" + attrName + "]");

}

}

 

returnwac;

}

 

initWebApplicationContext()方法可以看出,基本上如果ContextLoaderListener 加载了上下文将作为根

上下文(DispatcherServlet 的父容器)。

最后调用了onRefresh()方法执行容器的一些初始化,这个方法由子类实现,来进行扩展。

 

 

3、DispatcherServlet 继承 FrameworkServlet,并实现了onRefresh()方法提供一些前端控制器相关的配置:

 

/**

 * This implementation calls {@link#initStrategies}.

 */

@Override

protectedvoid onRefresh(ApplicationContext context) {

initStrategies(context);

}

 

/**

 * Initialize the strategy objects that thisservlet uses.

 * <p>May be overridden in subclasses inorder to initialize further strategy objects.

 */

protectedvoid initStrategies(ApplicationContext context) {

initMultipartResolver(context);

initLocaleResolver(context);

initThemeResolver(context);

initHandlerMappings(context);

initHandlerAdapters(context);

initHandlerExceptionResolvers(context);

initRequestToViewNameTranslator(context);

initViewResolvers(context);

initFlashMapManager(context);

}

从如上代码可以看出,DispatcherServlet启动时会进行我们需要的 Web Bean的配置,如 HandlerMappingHandlerAdapter等,而且如果我们没有配置,还会给我们提供默认的配置。

 

从如上代码我们可以看出,整个DispatcherServlet初始化的过程和做了些什么事情,具体主要做了如下两件事情:

1初始化 Spring Web MVC使用的 Web上下文,并且可能指定父容器为(ContextLoaderListener加载了根上下文)

2、初始化DispatcherServlet使用的策略,如 HandlerMappingHandlerAdapter等。

 

 

DispatcherServlet会进行一些默认的配置,DispatcherServlet 的默认配置在 DispatcherServlet.properties(和 DispatcherServlet类在一个包下)中,而且是当 Spring配置文件中没有指定配置时使用的默认策略:

 

 

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.Acce

ptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.Fixe

dThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.B

eanNameUrlHandlerMapping,\

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

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpR

equestHandlerAdapter,\

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.serv

let.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.Intern

alResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.

SessionFlashMapManager

 

DispatcherServlet默认使用 WebApplicationContext 作为上下文,因此我们来看一下该上下文中有哪些特殊的 Bean:

1Controller:处理器/页面控制器,做的是MVC 中的 C 的事情,但控制逻辑转移到前端控制器了,用于对请求进行

处理;

2HandlerMapping:请求到处理器的映射,如果映射成功返回一个HandlerExecutionChain 对象(包含一个 Handler

处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象;如 BeanNameUrlHandlerMapping 将 URL 与 Bean

名字映射,映射成功的Bean 就是此处的处理器;

3HandlerAdapter:HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的

应用,从而很容易支持很多类型的处理器;如SimpleControllerHandlerAdapter 将对实现了 Controller 接口的

Bean进行适配,并且掉处理器的 handleRequest 方法进行功能处理;

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

如InternalResourceViewResolver将逻辑视图名映射为jsp视图;

5LocalResover:本地化解析,因为Spring 支持国际化,因此 LocalResover 解析客户端的 Locale 信息从而方便进行国

际化;

6ThemeResovler:主题解析,通过它来实现一个页面多套风格,即常见的类似于软件皮肤效果;

7MultipartResolver:文件上传解析,用于支持文件上传;

8HandlerExceptionResolver:处理器异常解析,可以将异常映射到相应的统一错误界面,从而显示用户友好的

界面(而不是给用户看到具体的错误信息);

9RequestToViewNameTranslator:当处理器没有返回逻辑视图名等相关信息时,自动将请求URL 映射为逻辑视

图名;

10FlashMapManager:用于管理 FlashMap 的策略接口,FlashMap 用于存储一个请求的输出,当进入另一个请求时

作为该请求的输入,通常用于重定向场景

 

0 0
原创粉丝点击