SpringMVC--DispatcherServlet
DispatcherServlet是前端控制器设计模式的实现。提供SpringMVC集中访问点,而且负责职责的分派,并且与SpringIOC 容器无缝集成,从而可以获得Spring所有的优点。如下图:DispatcherServlet主要的职责是调度,本身主要用于控制流程:1,文件上传解析2,通过HandlerMapping,将请求映射到处理(返回一个HandlerExecu
DispatcherServlet是前端控制器设计模式的实现。提供SpringMVC集中访问点,而且负责职责的分派,并且与Spring IOC 容器无缝集成,从而可以获得Spring所有的优点。如下图:
DispatcherServlet主要的职责是调度,本身主要用于控制流程:
1,文件上传解析
2,通过HandlerMapping,将请求映射到处理(返回一个HandlerExecutionChain,它包括一个处理器,多个HandlerInterceptor拦截器);
3,通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器)
4,通过ViewResolver解析逻辑视图名到具体视图实现
5,渲染具体视图
6,将异常讲给HandlerExceptionResolver来解析
DispatcherServlet在web.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初始化集成体系结构如下:
初始化顺序如下:
1,HttpServletBean继承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");
}
}
2、FrameworkServlet继承 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 的配置,如 HandlerMapping、HandlerAdapter 等,而且如果我们没有配置,还会给我们提供默认的配置。
从如上代码我们可以看出,整个DispatcherServlet 初始化的过程和做了些什么事情,具体主要做了如下两件事情:
1、 初始化 Spring Web MVC 使用的 Web 上下文, 并且可能指定父容器为(ContextLoaderListener 加载了根上下文) ;
2、初始化DispatcherServlet 使用的策略,如 HandlerMapping、HandlerAdapter 等。
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:
1、Controller:处理器/页面控制器,做的是MVC 中的 C 的事情,但控制逻辑转移到前端控制器了,用于对请求进行
处理;
2、HandlerMapping:请求到处理器的映射,如果映射成功返回一个HandlerExecutionChain 对象(包含一个 Handler
处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象;如 BeanNameUrlHandlerMapping 将 URL 与 Bean
名字映射,映射成功的Bean 就是此处的处理器;
3、HandlerAdapter:HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的
应用,从而很容易支持很多类型的处理器;如SimpleControllerHandlerAdapter 将对实现了 Controller 接口的
Bean进行适配,并且掉处理器的 handleRequest 方法进行功能处理;
4、ViewResolver:ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;
如InternalResourceViewResolver将逻辑视图名映射为jsp视图;
5、LocalResover:本地化解析,因为Spring 支持国际化,因此 LocalResover 解析客户端的 Locale 信息从而方便进行国
际化;
6、ThemeResovler:主题解析,通过它来实现一个页面多套风格,即常见的类似于软件皮肤效果;
7、MultipartResolver:文件上传解析,用于支持文件上传;
8、HandlerExceptionResolver:处理器异常解析,可以将异常映射到相应的统一错误界面,从而显示用户友好的
界面(而不是给用户看到具体的错误信息);
9、RequestToViewNameTranslator:当处理器没有返回逻辑视图名等相关信息时,自动将请求URL 映射为逻辑视
图名;
10、FlashMapManager:用于管理 FlashMap 的策略接口,FlashMap 用于存储一个请求的输出,当进入另一个请求时
作为该请求的输入,通常用于重定向场景
更多推荐
所有评论(0)