我们知道SpringMVC的入口是DispatcherServlet,想进一步了解springMVC的技术内幕就得从这个servlet着手
首先我们看下DispatcherServlet的Diagram关系图:
HttpServletBean继承自HttpServlet 覆写了 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);//通过BeanWrapper构造DispatcherServlet
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.
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
initServletBean() 在 FrameworkServlet 中覆写 主要是关联servlet到spring上下文中
DispatcherServlet覆写了 FrameworkServlet的 onRefresh方法
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);//请求映射处理初始化
initHandlerAdapters(context); //请求适配初始化
initHandlerExceptionResolvers(context);//处理异常初始化
initRequestToViewNameTranslator(context);
initViewResolvers(context);//视图解析 初始化
initFlashMapManager(context);
}
我们知道servlet处理请求 会根据请求方式不同 调用不同的方法 例如 doGet ,doPost等等,但最终还是都调用processRequest 而该方法会调用 doService方法
DispatcherServlet中的 doService方法:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// request域中设置一些属性
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
doDispatch(request, response);// 分发服务
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
从上面可以看到 doService方法大概分为4步:
1,保存现场,保存request快照,以便后续可以恢复
2,将需要的对象放入request中,以便后续使用
3,分发服务
4,恢复快照
doDispatch方法:
HandlerMethod内部handle的时候,使用各种
HandlerMethodArgumentResolver实现类处理HandlerMethod的参数,使用各种
HandlerMethodReturnValueHandler实现类处理返回值。 最终返回值被处理成ModelAndView
对象,这期间发生的异常会被HandlerExceptionResolver接口实现类进行处理