DispatcherServlet详细分析
目录
- 1. DispatcherServlet的作用分析
- 1.1 uml类图
- 2. DispatcherServlet的初始化分析
- 2.1 初始化流程
- 2.2 详细分析流程
- 3. DispatcherServlet的请求过程分析
- 3.1 从Servlet调用到DispatcherServlet流程
- 3.2 DispatcherServlet.doDispatch详细流程
基于spring版本3.2.16.RELEASE
1. DispatcherServlet的作用分析
1.1 uml类图
从类图, 可以看出DispatcherServlet其本质是Servlet, 其间接实现了ServletConfig:
public interface Servlet {void init(ServletConfig var1) throws ServletException;ServletConfig getServletConfig();void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;String getServletInfo();void destroy();
}public interface ServletConfig {String getServletName();ServletContext getServletContext();String getInitParameter(String var1);Enumeration<String> getInitParameterNames();
}
2. DispatcherServlet的初始化分析
2.1 初始化流程
解析是从web.xml开始, DispatcherServlet其本质是Servlet, 所以初始化是从Servlet.init()方法开始:
2.2 详细分析流程
下面从上面几个重要步骤详细分析, 初始化的工作:
- GenericServlet: init(ServletConfig config)
public void init(ServletConfig config) throws ServletException {this.config = config;this.init();//调用被子类HttpServletBean重写方法init()
}
- HttpServletBean: init()
为DispatcherServlet创建BeanWrapper, 从ServletConfig中获取Servlet的initParams, 并设置到BeanWrapper的PropertyValues中去, 如contextConfigLocation
字段等属性. 核心代码如下:
PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
this.initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
<servlet><servlet-name>webServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:web-appcontext.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet>
- FrameworkServlet: initWebApplicationContext()
创建并初始化WebApplicationContext (以下简称Mvc容器)
protected WebApplicationContext initWebApplicationContext() {WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());//父容器if (wac == null) {wac = this.createWebApplicationContext(rootContext);}if (!this.refreshEventReceived) {this.onRefresh(wac);}if (this.publishContext) {//FrameworkServlet.class.getName() + ".CONTEXT."+getServletName()String attrName = this.getServletContextAttributeName();this.getServletContext().setAttribute(attrName, wac);}return wac;
}protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {Class<?> contextClass = this.getContextClass();//未配置则默认为XmlWebApplicationContextConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);//初始化wac.setEnvironment(this.getEnvironment());//设置Environmentwac.setParent(parent);//设置父容器wac.setConfigLocation(this.getContextConfigLocation()); //设置Spring配置文件位置this.configureAndRefreshWebApplicationContext(wac);return wac;
}protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac){wac.setServletContext(this.getServletContext());//关联ServletContextwac.setServletConfig(this.getServletConfig());wac.setNamespace(this.getNamespace());//设置nameSpace为DispatcherServlet的nameSpacewac.addApplicationListener(new SourceFilteringListener(wac, new FrameworkServlet.ContextRefreshListener()));ConfigurableEnvironment env = wac.getEnvironment();//设置Environmentif (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment)env).initPropertySources(this.getServletContext(), this.getServletConfig());}this.postProcessWebApplicationContext(wac);this.applyInitializers(wac);wac.refresh();//初始化所有的bean
}
这里需要注意以下几个点:
1.如果在web.xml中配置了ContextLoaderListener, 则生成的Root ApplicationContext(以下简称Root容器)会从ServletContext属性里拿出来作为当前Mvc容器的parent父容器, 见代码:
public interface WebApplicationContext extends ApplicationContext {String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";//Root WebApplicationContext放在ServletContext属性里
public static WebApplicationContext getWebApplicationContext(ServletContext sc) {return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);}
}
Mvc容器也放在ServletContext属性里, 属性名称为FrameworkServlet.class.getName() + ".CONTEXT."+getServletName()
2.设置Mvc容器的contextConfigLocation
需要注意一个点, 如果web.xml没有配置文件, 最终Mvc容器配置文件默认取${servlet-name}-servlet.xml, 请参考: SpringMVC的默认配置文件位置
- DispatcherServlet: initStrategies()
主要的动作是初始化DispatcherServlet的9大对象, 从Mvc容器获取对应类型的对象, 部分找不到会有默认值
protected void initStrategies(ApplicationContext context) {this.initMultipartResolver(context);//无默认值this.initLocaleResolver(context);//有默认值this.initThemeResolver(context);//有默认值this.initHandlerMappings(context);//有默认值this.initHandlerAdapters(context);//有默认值this.initHandlerExceptionResolvers(context);//有默认值this.initRequestToViewNameTranslator(context);//有默认值this.initViewResolvers(context);//有默认值this.initFlashMapManager(context);//有默认值
}
各组件的默认值在DispatcherServlet.properties里定义.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolverorg.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolverorg.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMappingorg.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapterorg.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolverorg.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslatororg.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolverorg.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
- WebApplicationContext.refresh()
WebApplicationContext.refresh和普通的ApplicationContext.refresh相比, 有所增强
AbstractApplicationContext.java
public void refresh() throws BeansException, IllegalStateException {synchronized(this.startupShutdownMonitor) {this.prepareRefresh();ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();this.prepareBeanFactory(beanFactory);try {this.postProcessBeanFactory(beanFactory);//增强的方法this.invokeBeanFactoryPostProcessors(beanFactory);this.registerBeanPostProcessors(beanFactory);this.initMessageSource();this.initApplicationEventMulticaster();this.onRefresh();this.registerListeners();this.finishBeanFactoryInitialization(beanFactory);this.finishRefresh();} catch (BeansException var5) {//略}}}
AbstractRefreshableWebApplicationContext.java
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));beanFactory.ignoreDependencyInterface(ServletContextAware.class);beanFactory.ignoreDependencyInterface(ServletConfigAware.class);//注册request/session/globalSession等scope相关组件到Mvc容器WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);//将servlet相关组件注册到Mvc容器WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
ServletContextAwareProcessor.java
public class ServletContextAwareProcessor implements BeanPostProcessor {private ServletContext servletContext;private ServletConfig servletConfig;public ServletContextAwareProcessor(ServletContext servletContext, ServletConfig servletConfig) {this.servletContext = servletContext;this.servletConfig = servletConfig;if (servletContext == null && servletConfig != null) {this.servletContext = servletConfig.getServletContext();}}public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (this.servletContext != null && bean instanceof ServletContextAware) {((ServletContextAware)bean).setServletContext(this.servletContext);}if (this.servletConfig != null && bean instanceof ServletConfigAware) {((ServletConfigAware)bean).setServletConfig(this.servletConfig);}return bean;}
}
3. DispatcherServlet的请求过程分析
DispatcherServlet其本质是Servlet, 请求从web容器请求过来调用Servlet的service方法:
3.1 从Servlet调用到DispatcherServlet流程
Servlet.service() -> DispatcherServlet.doDispatch()
下图调用流程比较简单, 略
3.2 DispatcherServlet.doDispatch详细流程
贴出烂大街的处理流程图:
对应源码:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {ModelAndView mv = null;Exception dispatchException = null;try {//如果是上传请求,且注册了MultipartResolver//此处会解析文件绑定到request,替换request为MultipartRequestprocessedRequest = this.checkMultipart(request);multipartRequestParsed = processedRequest != request;//如果是@Controller类型的处理器,此处还有校验@RequestMapping注解的三个属性RequestMethod/Headers/ParamsmappedHandler = this.getHandler(processedRequest, false);//获取Handlerif (mappedHandler == null || mappedHandler.getHandler() == null) {this.noHandlerFound(processedRequest, response);return;}//获取HandlerAdapterHandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());String method = request.getMethod();//interceptors过滤器前置处理if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}//调用实际Handler处理请求mv = ha.handle(processedRequest, response, mappedHandler.getHandler());this.applyDefaultViewName(request, mv);mappedHandler.applyPostHandle(processedRequest, response, mv);//过滤器后置} catch (Exception var20) {dispatchException = var20;}//渲染view或处理异常this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);} catch (Exception e){//略}
}
相关参考:
DefaultAnnotationHandlerMapping详细分析
HandlerInterceptor过滤器详细分析
DispatcherServlet详细分析相关推荐
- Yolov1目标检测算法详细分析
Yolov1目标检测算法详细分析 Yolov1介绍 这是继RCNN,fast-RCNN 和 faster-RCNN之后,rbg(Ross Girshick)大神挂名的又一大作,起了一个很娱乐化的名字: ...
- 详细分析本机号码一键登录原理
详细分析本机号码一键登录原理! 很多 APP 的目前都支持「本机号码一键登录」功能.本机号码一键登录是基于运营商独有网关认证能力推出的账号认证产品.用户只需一键授权,即可实现以本机号码注册/登录,相比 ...
- linux shell数据重定向(输入重定向与输出重定向)详细分析
转载自: linux shell数据重定向(输入重定向与输出重定向)详细分析 - 程默 - 博客园 http://www.cnblogs.com/chengmo/archive/2010/10/20/ ...
- Blueprint代码详细分析-Android10.0编译系统(七)
摘要:Blueprint解析Android.bp到ninja的代码流程时如何走的? 阅读本文大约需要花费18分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Andro ...
- android 串口开发_详细分析Esp8266上电信息打印的数据,如何做到串口通讯上电不乱码打印...
01 写在前面: 上篇关于如何在内置仅1M的Esp8285做到 OTA 升级的同步到微信公众号,竟然被安信可的某些运维人员看到了,想要转载,我很欣慰,竟然自己的笔记可以被这么大型的公司员工认可! 我是 ...
- C语言中的static 详细分析
google了近三页的关于C语言中static的内容,发现可用的信息很少,要么长篇大论不知所云要么在关键之处几个字略过,对于想挖掘底层原理的初学者来说参考性不是很大.所以,我这篇博文博采众家之长,把互 ...
- 【数字信号处理】序列傅里叶变换 ( 序列傅里叶变换定义详细分析 | 证明单位复指数序列正交完备性 | 序列存在傅里叶变换的性质 | 序列绝对可和 → 序列傅里叶变换一定存在 )
文章目录 一.序列傅里叶变换定义详细分析 二.证明单位复指数序列正交完备性 三.序列存在傅里叶变换的性质 一.序列傅里叶变换定义详细分析 序列傅里叶变换 SFT , 英文全称 " Seque ...
- 新手向:从不同的角度来详细分析Redis
最近对华为云分布式缓存产品Redis做了一些研究,于是整理了一些基本的知识拿出来与大家分享,首先跟大家分享的是,如何从不同的角度来详细使用Redis. 小编将从以下9个角度来进行详细分析,希望可以帮到 ...
- C语言中static详细分析
google了近三页的关于C语言中static的内容,发现可用的信息很少,要么长篇大论不知所云要么在关键之处几个字略过,对于想挖掘底层原理的初学者来说参考性不是很大.所以,我这篇博文博采众家之长,把互 ...
最新文章
- LF将由git中的CRLF替换-那是什么,它很重要吗? [重复]
- CISCO 组播RPF 逆向路径转发 实验原理
- Mac 上 Sublime Text3-Package control-console安装失败解决方案
- 第二章 系统设置及基本操作
- 每天进步一点点《ML - DBSCAN》
- 利用Python定时给女友微信发送今日天气情况,异地恋维护感情神器
- Libcurl的编译_HTTP/HTTPSclient源代码演示样例
- 电力设备巡检管理系统
- 希尔密码_希尔密码| 网络安全
- python操作QQ
- artDialog对话框组件使用方法
- C fork introduce
- C# 电脑麦克风录音
- 【转】校招优秀简历和普通简历的区别
- Linux 限制IP访问与白名单
- Python selenium 爬取淘宝商品
- vvic API 接入说明
- 贾跃亭自救 FF签约投行斯提夫尔加速推进全球融资
- CICS集群安装相关要点记录
- VIN码含义及其算法