Spirng 源代码学习笔记 Web 篇(一)DispatcherServlet
Spring MVC 将控制器、模型 、视图进行了很好的分离,请求的粗略处理过程如下图:
图中的 Front controller 指的就是
org.springframework.web.servlet.DispatcherServlet
DispatcherServlet 是请求的唯一入口,控制着 MVC 的整个流程。
一个 http 请求被 DispatcherServlet 拦截时,首先,根据 http 方法会映射到父类 FrameworkServlet 对应的 doGet、doPost、doPut 等方法上,最后都会转到 processRequest 方法,
然后调用 DispatcherServlet 的 doService 方法:
/** * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch} * for the actual dispatching. */ @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { String requestUri = urlPathHelper.getRequestUri(request); logger.debug("DispatcherServlet with name '" + getServletName() + "' processing " + request.getMethod() + " request for [" + requestUri + "]"); } // 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)) { logger.debug("Taking snapshot of request attributes before include"); 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)); } } } // Make framework objects available to handlers and view objects. 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()); try { doDispatch(request, response); } finally { // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } }
该方法绑定部分常用信息到当前线程,便于在后续处理中共享信息。然后调用 doDispatch 方法
/** * Process the actual dispatching to the handler. * <p>The handler will be obtained by applying the servlet's HandlerMappings in order. * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters * to find the first that supports the handler class. * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers * themselves to decide which methods are acceptable. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure */ protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; int interceptorIndex = -1; try { ModelAndView mv; boolean errorView = false; try { processedRequest = checkMultipart(request); // Determine handler for the current request. mappedHandler = getHandler(processedRequest, false); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { String requestUri = urlPathHelper.getRequestUri(request); logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // Apply preHandle methods of registered interceptors. HandlerInterceptor[] interceptors = mappedHandler.getInterceptors(); if (interceptors != null) { for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) { triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null); return; } interceptorIndex = i; } } // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // Do we need view name translation? if (mv != null && !mv.hasView()) { mv.setViewName(getDefaultViewName(request)); } // Apply postHandle methods of registered interceptors. if (interceptors != null) { for (int i = interceptors.length - 1; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv); } } } catch (ModelAndViewDefiningException ex) { logger.debug("ModelAndViewDefiningException encountered", ex); mv = ex.getModelAndView(); } catch (Exception ex) { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(processedRequest, response, handler, ex); errorView = (mv != null); } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { render(mv, processedRequest, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isDebugEnabled()) { logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + "': assuming HandlerAdapter completed request handling"); } } // Trigger after-completion for successful outcome. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null); } catch (Exception ex) { // Trigger after-completion for thrown exception. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex); throw ex; } catch (Error err) { ServletException ex = new NestedServletException("Handler processing failed", err); // Trigger after-completion for thrown exception. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex); throw ex; } finally { // Clean up any resources used by a multipart request. if (processedRequest != request) { cleanupMultipart(processedRequest); } } }
getHandler 根据请求 以及 handlerMapping 映射到实际的处理类(即 Controller),找到对应的 HandlerAdapter 。
如果存在 HandlerInterceptor ,则在调用实际处理类前,调用 preHandler方法;在完成后,调用 postHandler。
调用实际 Controller 后,返回的视图一般只是视图的名称。viewResolve 会根据名称解析实际的视图对象,然后调用视图对象的 render 方法进行实际的视图渲染。这样,视图的解析、渲染过程和请求的处理过程就分开了,互不影响。
DispatcherServlet 初始化
DispatcherServlet 是定义在 web.xml 中的 Servlet ,在服务器启动时调用父类 HttpServletBean 的 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); ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader)); 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"); } }
首先,设置 Servlet 配置,然后调用 FrameworkServlet 的 initServletBean() ,initServletBean()中调用 initWebApplicationContext () 创建 Spring 应用上下文 ,
protected WebApplicationContext initWebApplicationContext() { WebApplicationContext wac = findWebApplicationContext(); if (wac == null) { // No fixed context defined for this servlet - create a local one. WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); wac = createWebApplicationContext(parent); } if (!this.refreshEventReceived) { // Apparently not a ConfigurableApplicationContext with refresh support: // triggering initial onRefresh manually here. onRefresh(wac); } if (this.publishContext) { // Publish the context as a servlet context attribute. String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); if (this.logger.isDebugEnabled()) { this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() + "' as ServletContext attribute with name [" + attrName + "]"); } } return wac; }
创建完成后调用 DispatcherServlet 的 onRefresh(wac) 方法进行 DispatcherServlet 的初始化工作。
/** * 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); }
初始化中的每个方法负责初始化一个类型的组件,这些组件用户都可以自定义。当没有自定义时,自动根据 DispatcherServlet.properties 文件中配置的类型进行初始化。配置多个的,说明该项组件可以是一个集合。
# Default implementation classes for DispatcherServlet's strategy interfaces. # Used as fallback when no matching beans are found in the DispatcherServlet context. # Not meant to be customized by application developers. org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ 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.servlet.view.DefaultRequestToViewNameTranslator org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
默认的 HandlerMapping 为根据 url 映射为 Controller 的 BeanName,以及注解解析类;注解解析类在创建时会解析 spring 上下文中所有的类,解析类或方法上标注的 @RequestMapping,以后将其中的 url 都映射为对应的 Handler。
默认的视图解析类为 jsp 解析类。
至此,DispatcherServlet 的初始化工作完成。
相关推荐
"Spring笔记示例源代码"这个资源很可能是为了帮助学习者深入理解Spring框架的各种功能和用法而提供的实际代码示例。 1. **Spring IoC**:IoC是Spring的核心特性,它将对象的创建和管理权交给Spring容器,使得开发者...
在"Spring笔记.pdf"、"Spring笔记1.pdf"和"Spring编程学习笔记2.pdf"中,你将找到关于这些概念的详细解释和实例,包括XML配置、注解驱动的编程、AOP的实现方式、Spring Boot的快速启动指南以及Spring MVC的...
这个压缩包“Spring MVC学习笔记MD.7z”包含了作者在学习Spring MVC过程中的笔记、源代码以及相关文档,非常适合初学者或希望深入理解Spring MVC的开发者。 首先,`SpringMVC-Study.7z` 可能是作者整理的Spring MVC...
Spring框架是Java开发中广泛应用的一个轻量级框架,它的核心特性是依赖注入(Dependency Injection,DI),这使得组件之间的耦合度大大降低,提高了代码的可测试性和可维护性。Spring框架提供了大量的功能模块,包括...
《尚硅谷spring5视频笔记》是一份详尽的Spring框架第五版的学习资料,它涵盖了Spring 5的关键概念、新特性和实战应用。Spring是Java领域中最流行的企业级应用框架之一,Spring 5作为其最新版本,引入了许多重要的...
本学习笔记旨在深入探讨Spring框架的主要概念和功能,帮助读者从基础到进阶全面掌握Spring。 一、Spring概述 Spring是一个开源的Java平台,它提供了全面的企业级应用开发解决方案,包括数据访问、事务管理、远程...
4. **Spring MVC**:Spring 提供了一个用于构建 Web 应用的模块——Spring MVC。它遵循 Model-View-Controller 设计模式,使得开发人员能够清晰地分离业务逻辑、数据模型和用户界面。Spring MVC 包括 ...
在本篇【原创】Mybatis学习笔记(一)——Spring集成Mybatis中,我们将探讨如何将流行的持久层框架Mybatis与Spring框架进行整合,以便在实际项目开发中实现灵活、高效的数据库操作。以下是对相关知识点的详细说明: ...
Spring MVC 是一个用于构建 Web 应用的轻量级框架,它包含了一系列组件,如控制器(Controller)、验证器(Validator)、命令对象(Command Object)、表单对象(Form Object)、模型对象(Model Object)、分发器...
**JSF2整合Spring3——JSF学习笔记4** 在Java服务器端开发中,JavaServer Faces(JSF)和Spring框架都是重要的技术。JSF是一个用于构建用户界面的MVC(Model-View-Controller)框架,而Spring则是一个全面的企业级...
本笔记将深入探讨Spring框架的关键概念和技术,帮助你掌握这一强大的工具。 1. **依赖注入(Dependency Injection,DI)**: DI是Spring的核心特性,它允许我们解耦组件之间的关系,通过外部容器来管理对象的创建...
4. **Spring MVC**:如果涉及Web开发,可能会介绍Spring的Model-View-Controller架构,包括DispatcherServlet、控制器(Controller)、模型对象、视图解析等。 5. **Spring的IoC容器**:深入理解IoC容器的工作原理...
Spring的AOP支持在不修改源代码的情况下,对代码进行功能增强,如日志记录、事务管理等。AOP的关键概念包括: - **切面(Aspect)**:业务流程中的一个关注点,可以横切多个对象。 - **连接点(Joinpoint)**:程序...
AOP则是Spring提供的另一种强大工具,它允许我们在不修改源代码的情况下,对程序进行功能增强。比如,我们可以通过AOP实现日志记录、事务管理、性能监控等横切关注点。Spring AOP支持使用注解定义切面,简化了切面的...
- "SSM框架整合教程:一、MyBatis——尚硅谷学习笔记 2022 年.md":Markdown格式的学习笔记,详细记录了教程中的关键知识点和步骤。 - "SSM框架整合教程:一、MyBatis——尚硅谷学习笔记 2022 年.pdf":PDF版本的...
尚硅谷的 Spring Boot 笔记涵盖了以上这些核心概念,并可能深入到实际应用案例、问题解决、最佳实践等方面,对于学习和进阶 Spring Boot 的开发者来说是一份宝贵的资源。通过阅读这些笔记,你可以更好地理解 Spring ...
3. Spring MVC:Spring MVC是Spring框架的一部分,它是一个模型-视图-控制器(MVC)架构,用于开发Web应用程序。Spring MVC通过分离关注点,简化了Web开发,允许开发者专注于业务逻辑,而无需关心基础设施细节。它...
- **Spring Web**:提供了 Web 应用程序开发所需的支持,如 ServletListener、DispatcherServlet 等。 - **Spring MVC**:这是一个用于构建 Web 应用程序的模型-视图-控制器框架,它是 Spring Web 模块的一部分,...
5. **Spring MVC**:对于Web应用,Spring MVC是Spring提供的一个用于构建MVC模式的框架。我们将学习DispatcherServlet、Controller、ModelAndView、视图解析器等核心组件,以及如何处理HTTP请求和响应。 6. **...
这个"ssm.zip_2Y7_ssm_ssm学习笔记_ssm整合"压缩包文件很可能是某个开发者的学习资料,包含了他对SSM整合的理解和实践总结。以下是对SSM整合及相关知识点的详细解释。 1. **Spring框架**:Spring是一个全面的Java...