资讯专栏INFORMATION COLUMN

由DispatcherServlet看spring mvc请求处理过程

justjavac / 1968人阅读

摘要:封装了方法,关键就是前一部分是将当前请求的对象和属性,分别设置到和这两个抽象类中的对象中,也就是分别将这两个东西和请求线程做了绑定。方法本质是执行方法是一个抽象类,方法调用,是一个接口,在实现类中实现。

DispatcherServlet来看spring mvc请求处理过程 架构

官方架构图

可以看到请求处理过程,而DispatcherServlet正是担当front controller的角色。

生命周期

通过源码可以看到,DispatcherServlet继承自FrameworkServlet,FrameworkServlet继承HttpServletBean,HttpServletBean继承HttpServlet。
而Servlet生命周期的三个阶段就是【init-service-destroy】
所以对DispatcherServlet而言,类似最初进行servlet编程。继承HttpServlet,重写doGet、doPost,在方法中跳转到jsp页面,利用注解或者在xml文件中注册Servlet。

初始化

在HttpServletBean中,覆写了HttpServlet类的init()方法。
前面是将web.xml中在DispatcherServlet这个Servlet下面的配置元素利用JavaBean的方式(即通过setter方法)读取到DispatcherServlet中来
值得一提的是其中有一句

</>复制代码

  1. initServletBean();

但是在HttpServletBean中是一个空方法,留给子类来实现,这就是模版方法,在父类中定义执行流程,把可变的部分留给子类实现。体现了开闭原则。

initServletBean在FrameworkServlet中关键的一句

</>复制代码

  1. this.webApplicationContext = initWebApplicationContext();

所以FrameworkServlet存在的意义也用来抽离出建立 WebApplicationContext 上下文这个过程的。建立一个和Servlet关联的Spring容器上下文,并将其注册到ServletContext中。

因为DispatcherServlet重写了onRefresh,建立上下文后,通过onRefresh(ApplicationContext context)方法的回调,进入到DispatcherServlet类
onRefresh方法中initStrategies()封装了初始化策略
以detectAllHandlerMappings为例,detectAllHandlerMappings默认为true,把上下文中所有HandlerMapping类型的Bean都注册在handlerMappings这个List变量中。

总结:HttpServletBean完成的是配置元素的依赖注入,FrameworkServlet完成的是容器上下文的建立,DispatcherServlet完成的是SpringMVC具体编程元素的初始化策略。

Service

以Get请求为例,经过HttpServlet基类中service()方法的委派,请求会被转发到doGet()方法中。doGet()方法,在DispatcherServlet的父类FrameworkServlet类中被重写。
封装了processRequest方法,关键就是doService(request, response);
前一部分是将当前请求的Locale对象和属性,分别设置到LocaleContextHolder和RequestContextHolder这两个抽象类中的ThreadLocal对象中,也就是分别将这两个东西和请求线程做了绑定。在doService()处理结束后,再恢复回请求前的LocaleContextHolder和RequestContextHolder,也即解除线程绑定。每次请求处理结束后,容器上下文都发布了一个ServletRequestHandledEvent事件,你可以注册监听器来监听该事件。

只是做了一些线程安全的隔离。

doService又是一个抽象方法。子类实现。实现在DispatcherServlet中
doDispatch(request, response);
几个requet.setAttribute()方法的调用,将前面在初始化流程中实例化的对象设置到http请求的属性中,供下一步处理使用,其中有容器的上下文对象、本地化解析器等SpringMVC特有的编程元素。

doDispatch中

mappedHandler = getHandler(processedRequest);获得处理请求的handler,返回HandlerExecutionChain
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());获得处理请求的handler adapter
mappedHandler.applyPreHandle(processedRequest, response执行interceptor的prehandle方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());实际调用handler,返回ModelAndView
applyDefaultViewName(processedRequest, mv);设置view的名字

mappedHandler.applyPostHandle(processedRequest, response, mv);执行intercepter的postHandle方法,
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);发送结果

数据结构

HandlerMapping、HandlerAdapter、View这些接口的设计。
HandlerAdapter:是一个接口。support方法根据类型来判断该adapter是否支持handler实例,handle方法用给定的handler处理请求;

</>复制代码

  1. public interface HandlerAdapter {
  2. boolean supports(Object handler);
  3. ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
  4. long getLastModified(HttpServletRequest request, Object handler);
  5. }

HandlerMapping接口中:
getHandler获取请求的handler和所有interceptors,返回HandlerExecutionChain的对象

</>复制代码

  1. public interface HandlerMapping {
  2. String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
  3. String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
  4. String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
  5. //...
  6. HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

View接口:
主要是render方法
void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception;

HandlerExecutionChain:主要包含 interceptors的list,和一个handle,这里handler是由Object对象来引用的,没有绑定任何接口,这里说明了任何对象都可以作为最后的处理对象来生成视图
ModelAndView是处理的结果,主要包含Object引用的view,和ModelMap引用的model。view可以是view名(String)或者是一个view的实例。ModelMap继承LinkedHashMap,也就是一个map,放了属性名和属性值。

HandlerInterceptor这个接口,定义了拦截器的实现
preHandle,postHandle,afterCompletion就像刚刚在doDispatch中一样,环绕着hanlder实现,分别在handler执行前,执行后和渲染后执行。

</>复制代码

  1. public interface HandlerInterceptor {
  2. boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception;
  3. void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception;
  4. void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception;
  5. }
深入处理流程
mappedHandler

mappedHandler = getHandler(processedRequest);
可以看出getHandler方法就是遍历初始化时已经获取的handlerMappings,如果找到一个HandlerMapping,getHandler方法返回的不为null,那么说明找到了这个mappedHandler,并返回。

</>复制代码

  1. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  2. for (HandlerMapping hm : this.handlerMappings) {
  3. if (logger.isTraceEnabled()) {
  4. logger.trace(
  5. "Testing handler map [" + hm + "] in DispatcherServlet with name "" + getServletName() + """);
  6. }
  7. HandlerExecutionChain handler = hm.getHandler(request);
  8. if (handler != null) {
  9. return handler;
  10. }
  11. }
  12. return null;
  13. }

getHandler的实现在AbstractHandlerMapping类中,根据request找到Handler和Interceptor,组合成HandlerExecutionChain类型并返回

</>复制代码

  1. @Override
  2. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  3. Object handler = getHandlerInternal(request);
  4. if (handler == null) {
  5. handler = getDefaultHandler();
  6. }
  7. if (handler == null) {
  8. return null;
  9. }
  10. // Bean name or resolved handler?
  11. if (handler instanceof String) {
  12. String handlerName = (String) handler;
  13. handler = getApplicationContext().getBean(handlerName);
  14. }
  15. HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
  16. if (CorsUtils.isCorsRequest(request)) {
  17. CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
  18. CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
  19. CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
  20. executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
  21. }
  22. return executionChain;
  23. }

getHandlerInternal是个接口
AbstractHandlerMethodMapping,AbstractUrlHandlerMapping都实现了它。其中AbstractHandlerMethodMapping更常用,注解@RequestMapping的方式就属于它,它将被注解的Method作为handler。

</>复制代码

  1. protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;

lookupHandlerMethod方法来查找url和对应的方法

</>复制代码

  1. @Override
  2. protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
  3. String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
  4. this.mappingRegistry.acquireReadLock();
  5. try {
  6. HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
  7. return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
  8. }
  9. finally {
  10. this.mappingRegistry.releaseReadLock();
  11. }
  12. }

从mappingRegistry中获取匹配路径的mapping,并排序获取最匹配的handlerMethod

</>复制代码

  1. protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
  2. List matches = new ArrayList();
  3. List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
  4. if (directPathMatches != null) {
  5. addMatchingMappings(directPathMatches, matches, request);
  6. }
  7. if (matches.isEmpty()) {
  8. // No choice but to go through all mappings...
  9. addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
  10. }
  11. if (!matches.isEmpty()) {
  12. Comparator comparator = new MatchComparator(getMappingComparator(request));
  13. Collections.sort(matches, comparator);
  14. Match bestMatch = matches.get(0);
  15. if (matches.size() > 1) {
  16. if (CorsUtils.isPreFlightRequest(request)) {
  17. return PREFLIGHT_AMBIGUOUS_MATCH;
  18. }
  19. Match secondBestMatch = matches.get(1);
  20. if (comparator.compare(bestMatch, secondBestMatch) == 0) {
  21. Method m1 = bestMatch.handlerMethod.getMethod();
  22. Method m2 = secondBestMatch.handlerMethod.getMethod();
  23. throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path "" +
  24. request.getRequestURL() + "": {" + m1 + ", " + m2 + "}");
  25. }
  26. }
  27. handleMatch(bestMatch.mapping, lookupPath, request);
  28. return bestMatch.handlerMethod;
  29. }
  30. else {
  31. return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
  32. }
  33. }
getHandlerAdapter

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

同样也是遍历handlerAdapters中所有的adapter,如果和handler的类型匹配,就返回handlerAdapter

</>复制代码

  1. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
  2. for (HandlerAdapter ha : this.handlerAdapters) {
  3. if (ha.supports(handler)) {
  4. return ha;
  5. }
  6. }
  7. throw new ServletException("No adapter for handler [" + handler +
  8. "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
  9. }
applyPreHandle

mappedHandler.applyPreHandle(processedRequest, response依次执行interceptor的prehandle方法,如果又一个拦截器返回false就停止

</>复制代码

  1. boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
  2. HandlerInterceptor[] interceptors = getInterceptors();
  3. if (!ObjectUtils.isEmpty(interceptors)) {
  4. for (int i = 0; i < interceptors.length; i++) {
  5. HandlerInterceptor interceptor = interceptors[i];
  6. if (!interceptor.preHandle(request, response, this.handler)) {
  7. triggerAfterCompletion(request, response, null);
  8. return false;
  9. }
  10. this.interceptorIndex = i;
  11. }
  12. }
  13. return true;
  14. }
handle

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

这个方法在handlerAdapter的接口中,有几个实现,AbstractHandlerMethodAdapter,AnnotationMethodHandlerAdapter,,,
SimpleServletHandlerAdapter:handle方法就是调用Servlet的service((Servlet) handler).service(request, response);
SimpleControllerHandlerAdapter:handle方法本质是执行Controller.handleRequest方法return ((Controller) handler).handleRequest(request, response);
HttpRequestHandlerAdapter: ((HttpRequestHandler) handler).handleRequest(request, response);
AbstractHandlerMethodAdapter:是一个抽象类,handle方法调用handleInternal,handleInternal是一个接口,在实现类RequestMappingHandlerAdapter中实现。关键的地方在于调用invokeHandlerMethod

</>复制代码

  1. @Override
  2. protected ModelAndView handleInternal(HttpServletRequest request,
  3. HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  4. ModelAndView mav;
  5. checkRequest(request);
  6. //...
  7. mav = invokeHandlerMethod(request, response, handlerMethod);
  8. //..
  9. prepareResponse(response);
  10. //..
  11. return mav;
  12. }

invokeHandlerMethod就是在执行传入的handler方法

</>复制代码

  1. protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
  2. HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  3. .........
  4. //执行Controller中的RequestMapping注释的方法
  5. invocableMethod.invokeAndHandle(webRequest, mavContainer);
  6. //返回ModelAndView视图
  7. return getModelAndView(mavContainer, modelFactory, webRequest);
  8. }
applyDefaultViewName

applyDefaultViewName(processedRequest, mv);
很简单,就是设置一下view

</>复制代码

  1. private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception {
  2. if (mv != null && !mv.hasView()) {
  3. mv.setViewName(getDefaultViewName(request));
  4. }
  5. }
applyPostHandle

同上applyPreHandle,执行拦截器list中的postHandle方法

processDispatchResult

关键就是调用render方法,然后执行拦截器列表中的AfterCompletion方法

</>复制代码

  1. private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
  2. HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
  3. boolean errorView = false;
  4. if (exception != null) {
  5. if (exception instanceof ModelAndViewDefiningException) {
  6. logger.debug("ModelAndViewDefiningException encountered", exception);
  7. mv = ((ModelAndViewDefiningException) exception).getModelAndView();
  8. }
  9. else {
  10. Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
  11. mv = processHandlerException(request, response, handler, exception);
  12. errorView = (mv != null);
  13. }
  14. }
  15. // Did the handler return a view to render?
  16. if (mv != null && !mv.wasCleared()) {
  17. render(mv, request, response);
  18. }
  19. if (mappedHandler != null) {
  20. mappedHandler.triggerAfterCompletion(request, response, null);
  21. }
  22. }

render方法中,关键的一步view.render(mv.getModelInternal(), request, response);
这个接口在AbstractView这个抽象类中定义了模版方法

</>复制代码

  1. @Override
  2. public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
  3. Map mergedModel = createMergedOutputModel(model, request, response);
  4. prepareResponse(request, response);
  5. renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
  6. }

createMergedOutputModel,关键是这些putAll方法,把静态的attribute和动态值方都放进mergedModel中然后返回,可以看到先put staticAttributes后put model,所以说明动态的值优先级更高可能覆盖静态attribute的值

</>复制代码

  1. protected Map createMergedOutputModel(Map model, HttpServletRequest request,
  2. HttpServletResponse response) {
  3. ...
  4. Map mergedModel = new LinkedHashMap(size);
  5. mergedModel.putAll(this.staticAttributes);
  6. if (pathVars != null) {
  7. mergedModel.putAll(pathVars);
  8. }
  9. if (model != null) {
  10. mergedModel.putAll(model);
  11. }
  12. // Expose RequestContext?
  13. if (this.requestContextAttribute != null) {
  14. mergedModel.put(this.requestContextAttribute, createRequestContext(request, response, mergedModel));
  15. }
  16. return mergedModel;
  17. }

prepareResponse就是设置response头

</>复制代码

  1. protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) {
  2. if (generatesDownloadContent()) {
  3. response.setHeader("Pragma", "private");
  4. response.setHeader("Cache-Control", "private, must-revalidate");
  5. }
  6. }

renderMergedOutputModel又是一个接口
protected abstract void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception;

有很多实现,对于jsp,在InternalResourceView类中实现

</>复制代码

  1. @Override
  2. protected void renderMergedOutputModel( Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
  3. // Expose the model object as request attributes.
  4. exposeModelAsRequestAttributes(model, request);
  5. // Expose helpers as request attributes, if any.
  6. exposeHelpers(request);
  7. // Determine the path for the request dispatcher.
  8. String dispatcherPath = prepareForRendering(request, response);
  9. // Obtain a RequestDispatcher for the target resource (typically a JSP).
  10. RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
  11. // If already included or response already committed, perform include, else forward.
  12. if (useInclude(request, response)) {
  13. response.setContentType(getContentType());
  14. rd.include(request, response);
  15. }
  16. else {
  17. // Note: The forwarded resource is supposed to determine the content type itself.
  18. rd.forward(request, response);
  19. }
  20. }

exposeModelAsRequestAttributes方法就是把model中的值都填到request中

</>复制代码

  1. protected void exposeModelAsRequestAttributes(Map model, HttpServletRequest request) throws Exception {
  2. for (Map.Entry entry : model.entrySet()) {
  3. String modelName = entry.getKey();
  4. Object modelValue = entry.getValue();
  5. if (modelValue != null) {
  6. request.setAttribute(modelName, modelValue);
  7. }
  8. else {
  9. request.removeAttribute(modelName);
  10. }
  11. }
  12. }

如果response已经提交了,included,否则就执行forward
到这里,请求处理结束。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/66702.html

相关文章

  • spring MVC -- controller参数的解析

    摘要:是提供的类,为了在容器中建立容器而服务的。主要处理的请求分发,对进行管理。接收到请求由进行匹配,匹配成功后交由进行业务逻辑的处理,业务逻辑处理完成后交由进行数据的解析同时找到对应的,最终由将的结果到浏览器进行解析。 spring给我们带来了什么? spring IoC、AOP、Transaction这些都是很重要的特性,但是这篇这些都不是主角,主要来谈谈springMVC是如何对请求参...

    suemi 评论0 收藏0
  • “过时”的SpringMVC我们到底在用什么?深入分析DispatchServlet源码

    摘要:问题来了,我们到底还在用吗答案是,不全用。后者是初始化的配置,主要是的配置。启动类测试启动项目后,在浏览器里面输入。通过查询已装载的,并且支持该而获取的。按照前面对的描述,对于而言,这个必定是。的核心在的方法中。 之前已经分析过了Spring的IOC(《零基础带你看Spring源码——IOC控制反转》)与AOP(《从源码入手,一文带你读懂Spring AOP面向切面编程》)的源码,本次...

    array_huang 评论0 收藏0
  • Spring之旅第十站:MVC配置、上传文件、异常处理、跨重定向请求、为控制器添加通知

    摘要:依赖于对请求的支持。使用解析兼容的没有构造器参数,也没有要设置的参数,这样,在应用上下文中,将其声明为就会非常简单。默认是没有限制的整个请求的容量。 Spring MVC 高级的技术 本章内容: Spring MVC配置的替代方案 处理文件上传 在控制器中处理异常 使用flash属性 稍等还没结束 说明 如果你有幸能看到。后面的章节暂时不更新了,改变学习方式了。重要理解思想,这本书...

    leanote 评论0 收藏0
  • 如何向一个WebApp引入SpringSpring MVC

    摘要:可以发现,这两个类都是可以被实例化的,且构造器不需要参数。这段代码的后半部分其实没有什么新意,但下半部分的第一行非常关键接受一个作为构造器参数这实际上解决了我们在第四章测试失败后反思的可能的疑惑我们配置的容器实际上并没有和融合起来。 如何向一个WebApp引入Spring与Spring MVC 1 在Servlet 3.0环境中,容器(加载运行webapp的软件,如Tomcat)会在类...

    maochunguang 评论0 收藏0
  • SpringMVC之源码分析--启动过程

    摘要:核心类类的继承关系前端控制器是规范中的核心类,实现接口,继承此类用于处理用户请求。主要配置中初始化参数。 Spring MVC 核心类 类的继承关系Spring MVC前端控制器DispatcherServlet-->FrameworkServlet-->HttpServletBean-->HttpServletshowImg(https://segmentfault.com/img/...

    Olivia 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<