spring mvc DispatcherServlet解读
DispatcherServlet的继承和实现
IDEA按快捷键:ctrl+alt+u,就可以查看DispatcherServlet的继承的类和实现的接口。
从继承图可以得知:
- DispatcherServlet本质是一个HttpServlet
- HttpServletBean,FrameworkServlet,DispatcherServlet是属于SpringMVC的类
DispatcherServlet初始化
DispatcherServlet
DispatcherServlet看initStrategies(),该方法用于初始化各类解析器。
onRefresh(ApplicationContext context),该方法用于刷新策略
/**
* 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.
*/
//初始化各类解析器
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context); //初始化分段上传解析器
initLocaleResolver(context); //初始化地域解析器
initThemeResolver(context); //初始化主题解析器
initHandlerMappings(context); //初始化处理器映射
initHandlerAdapters(context); //初始化处理器适配器
initHandlerExceptionResolvers(context); //初始化处理器异常解析器
initRequestToViewNameTranslator(context); //初始化请求到视图名解析器
initViewResolvers(context); //初始化视图解析器
initFlashMapManager(context); //初始化快闪映射
}
FrameworkServlet
onRefresh(ApplicationContext context)重写于父类FrameworkServlet,点开FrameworkServlet,我们主要看看它initServletBean()方法,FrameworkServlet的onRefresh(ApplicationContext context)是个空实现,因为在DispatcherServlet实现了。
initServletBean()是重写HttpServletBean的initServletBean(),先看看initServletBean()干了什么:
- 调用了initWebApplicationContext(),初始化了WebApplicationContext,而WebApplicationContext是继承于ApplicationContext接口的,所以我们知道了initWebApplicationContext是初始化了一个上下文。
- 调用了initFrameworkServlet(),点开发现是个空实现。
@Override
protected final void initServletBean() throws ServletException {
//*******查看核心部分**********
try {
//这里初始化WebApplicationContext
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet(); //空实现,给其他继承类实现
}
catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
//*******其他日志的不看********
}
点开initWebApplicationContext(),因为太长了,所以放图片。
上半段:
- 通过servlet上下文中创建了一个rootcontext
- 中间的if代码块在上下文刷新时才会运行,初始化状态时,webapplicationcontext是null,所以初始化时是不进入的。该段代码主要用于刷新上下文
下半段:
- 查找已经存在的注册的上下文,如果没有就用rootContex去创建一样上下文。
- refreshEventReceived默认是false
/** Flag used to detect whether onRefresh has already been called. */
private volatile boolean refreshEventReceived = false;
- onRefresh()方法被重写了,所以我们知道在Dispatchservlet中,会初始化各种解析器(如:视图解析器等)
HttpServletBean
假设WEB-INF 目录下查找配置文件信息如下:
<!-- 部署 DispatcherServlet -->
<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:springmvc-servlet.xml</param-value>
</init-param>
<!-- 表示容器再启动时立即加载servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
HttpServletBean是抽象类,ctrl+F12查看方法。
找到init()方法,这个是我们要找到的重要方法
- init()方法是重写了GenericServlet的init()方法,所以这个是最根本的初始化方法。
让我们看看init()干了什么:
ServletConfigPropertyValues是用来加载Servlet配置,ServletConfigPropertyValues是HttpServletBean的内部静态类,它负责取到web.xml中init-param(如:contextConfigLocation)
@Override
public final void init() throws ServletException {
//加载web.xml中init-param(如:contextConfigLocation)
// Set bean properties from init parameters.
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
//BeanWrapper将HttpServletBean进行包装
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
//ServletContext的资源加载器
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
//注册资源编辑器
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
//为HttpServletBean初始化包装,默认实现是空的
initBeanWrapper(bw);
//给包装类传递web.xml中init-param
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
// Let subclasses do whatever initialization they like.
//initServletBean()是交给子类实现的,FrameworkServlet实现了这个方法
initServletBean();
}
初始化总结
各类的初始化工作:
- HttpServletBean 主要初始化web.xml资源
- FrameworkServlet 获取servlet上下文创建WebApplicationContext
- DispatcherServlet 初始化各类解析器
调用过程
- HttpServletBean ---- init()
- FrameworkServlet ---- initServletBean()
- FrameworkServlet ---- initWebApplicationContext()
- DispatcherServlet ---- onRefresh(ApplicationContext context)
- DispatcherServlet ---- initStrategies(ApplicationContext context)
- DispatcherServlet ---- initXXX(ApplicationContext context)各种解析器组件的初始化
DispatcherServlet处理请求
核心成员变量
DispatcherServlet的核心成员变量就是上面DispatcherServlet初始化中initStrategies(ApplicationContext context)
初始化的各类处理器。
/** MultipartResolver used by this servlet. */
@Nullable
private MultipartResolver multipartResolver;
/** LocaleResolver used by this servlet. */
@Nullable
private LocaleResolver localeResolver;
/** ThemeResolver used by this servlet. */
@Nullable
private ThemeResolver themeResolver;
/** List of HandlerMappings used by this servlet. */
@Nullable
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet. */
@Nullable
private List<HandlerAdapter> handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet. */
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet. */
@Nullable
private RequestToViewNameTranslator viewNameTranslator;
/** FlashMapManager used by this servlet. */
@Nullable
private FlashMapManager flashMapManager;
/** List of ViewResolvers used by this servlet. */
@Nullable
private List<ViewResolver> viewResolvers;
doService()
在浏览器输入位置时,会触发DispatcherServlet
的doService(HttpServletRequest request, HttpServletResponse response)
去处理请求。
doService(HttpServletRequest request, HttpServletResponse response)
又会去调用doDispatch(HttpServletRequest request, HttpServletResponse response)
去处理请求
doDispatch()
doDispatch比较多代码分成两段截图
上半段代码
下半段代码
还有
getHandler()
getHandler()会遍历所有的handlerMapping,并找出匹配的handler。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
关于handlerMapping接口的实现类
handlerMapping接口的实现类有许多,RequestMappingHandlerMapping,该类用于创建@RequestMapping和@Controller注解的实例