Spring-MVC核心调用流程我都拿出来了,别再说把握不住DispatcherServlet-了

所在类:org.springframework.web.servlet. DispatcherServlet

  1. protected void onRefresh(ApplicationContext context) {

  2. initStrategies(context);

  3. }

  4. protected void initStrategies(ApplicationContext context) {

  5. // 初始化文件上传处理

  6. initMultipartResolver(context);

  7. // 初始化本地化 Resolver

  8. initLocaleResolver(context);

  9. // 初始化主题 Resolver

  10. initThemeResolver(context);

  11. // 初始化 URL映射关系

  12. initHandlerMappings(context);

  13. // 初始化Handler接口适配器

  14. initHandlerAdapters(context);

  15. // 初始化异常处理的 handler

  16. initHandlerExceptionResolvers(context);

  17. // 初始化请求路径转换

  18. initRequestToViewNameTranslator(context);

  19. // 初始化视图解析

  20. initViewResolvers(context);

  21. // 初始化 flashmap管理

  22. initFlashMapManager(context);

  23. }

::: warning 知识点 initStrategies方法中的所有初始化组件中之所以可以拿到值,主要是通过 @EnableWebMvc注解,调用到 WebMvcConfigurationSupport类中的各个 @Bean注解的方法,完成的实例化过程。:::

请求调用流程

当父子容器都启动完成后,开始进行请求的响应处理,

  • 请求 http://localhost:9090/user/queryUser地址

进入 service方法

所在类:javax.servlet.http. HttpServlet

  1. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

  2. String method = req.getMethod();

  3. long lastModified;

  4. if (method.equals("GET")) {

  5. lastModified = this.getLastModified(req);

  6. if (lastModified == -1L) {

  7. this.doGet(req, resp);

  8. }

  9. // ...... 省略

  10. }

进入 doGet方法

所在类:org.springframework.web.servlet. FrameworkServlet

  1. @Override

  2. protected final void doGet(HttpServletRequest request, HttpServletResponse response)

  3. throws ServletException, IOException {

  4. processRequest(request, response);

  5. }

进入 processRequest方法

所在类:org.springframework.web.servlet. FrameworkServlet

  1. protected final void processRequest(HttpServletRequest request, HttpServletResponse response)

  2. throws ServletException, IOException {

  3. long startTime = System.currentTimeMillis();

  4. Throwable failureCause = null;

  5. doService(request, response);

  6. }

进入 doService方法

所在类:org.springframework.web.servlet. DispatcherServlet

  1. protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {

  2. logRequest(request);

  3. try {

  4. // 调用核心流程

  5. doDispatch(request, response);

  6. }

  7. finally {

  8. if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {

  9. // Restore the original attribute snapshot, in case of an include.

  10. if (attributesSnapshot != null) {

  11. restoreAttributesAfterInclude(request, attributesSnapshot);

  12. }

  13. }

  14. }

  15. }

请求调用 核心入口

请求最终进入 doDispatch方法

所在类:org.springframework.web.servlet. DispatcherServlet

  1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

  2. HttpServletRequest processedRequest = request;

  3. HandlerExecutionChain mappedHandler = null;

  4. boolean multipartRequestParsed = false;

  5. // 异步管理

  6. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

  7. try {

  8. ModelAndView mv = null;

  9. Exception dispatchException = null;

  10. try {

  11. // 文件上传解析,如果请求类型是multipart将通过

  12. // MultipartResolver进行文件上传解析

  13. processedRequest = checkMultipart(request);

  14. multipartRequestParsed = (processedRequest != request);

  15. // 对当前请求匹配一个合适的 handler,重要方法

  16. mappedHandler = getHandler(processedRequest);

  17. if (mappedHandler == null) {

  18. noHandlerFound(processedRequest, response);

  19. return;

  20. }

  21. // Determine handler adapter for the current request.

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

  23. // Process last-modified header, if supported by the handler.

  24. String method = request.getMethod();

  25. boolean isGet = "GET".equals(method);

  26. if (isGet || "HEAD".equals(method)) {

  27. long lastModified = ha.getLastModified(request, mappedHandler.getHandler());

  28. if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {

  29. return;

  30. }

  31. }

  32. if (!mappedHandler.applyPreHandle(processedRequest, response)) {

  33. return;

  34. }

  35. // Actually invoke the handler.

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

  37. if (asyncManager.isConcurrentHandlingStarted()) {

  38. return;

  39. }

  40. applyDefaultViewName(processedRequest, mv);

  41. mappedHandler.applyPostHandle(processedRequest, response, mv);

  42. }

  43. catch (Exception ex) {

  44. dispatchException = ex;

  45. }

  46. catch (Throwable err) {

  47. dispatchException = new NestedServletException("Handler dispatch failed", err);

  48. }

  49. processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

  50. }

  51. catch (Exception ex) {

  52. triggerAfterCompletion(processedRequest, response, mappedHandler, ex);

  53. }

  54. catch (Throwable err) {

  55. triggerAfterCompletion(processedRequest, response, mappedHandler,

  56. new NestedServletException("Handler processing failed", err));

  57. }

  58. finally {

  59. if (asyncManager.isConcurrentHandlingStarted()) {

  60. // Instead of postHandle and afterCompletion

  61. if (mappedHandler != null) {

  62. mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);

  63. }

  64. }

  65. else {

  66. // 如果是multipart的请求,清空上传的multipart资源

  67. if (multipartRequestParsed) {

  68. cleanupMultipart(processedRequest);

  69. }

  70. }

  71. }

  72. }

::: warning 知识点总结, getHandler方法的主要作用体现在以下几点:

  • 首先,从当前Request中拿到请求的 URL

  • 然后,从映射关系中拿到 HandlerMethod对象

  • 接着,把 HandlerMethod对象封装到 HandlerExecutionChain执行链中

  • 最后,在 HandlerExecutionChain执行链的创建过程中会拿到整个容器中所有的拦截器(实现 HandlerInterceptor接口的 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 拦截器),和当前请求的 URL进行匹配,如果匹配成功的话,就会把拦截器放到 HandlerExecutionChain的数组中。:::

进入 getHandler方法

所在类:org.springframework.web.servlet. DispatcherServlet

  1. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

  2. // handlerMappering 实例容器不为空

  3. if (this.handlerMappings != null) {

  4. for (HandlerMapping mapping : this.handlerMappings) {

  5. // 获取 HandlerMethod 和过滤器链的包装类

  6. HandlerExecutionChain handler = mapping.getHandler(request);

  7. if (handler != null) {

  8. return handler;

  9. }

  10. }

  11. }

  12. return null;

  13. }

进入 getHandler方法

所在类:org.springframework.web.servlet.handler. AbstractHandlerMapping

  1. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

  2. // 根据请求的 URL 拿到对应的 HandlerMethod 对象

  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 = obtainApplicationContext().getBean(handlerName);

  14. }

  15. // 获取 HandlerMethod 和过滤器链的包装类

  16. HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

  17. if (logger.isTraceEnabled()) {

  18. logger.trace("Mapped to " + handler);

  19. }

  20. else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {

  21. logger.debug("Mapped to " + executionChain.getHandler());

  22. }

  23. // 是否是跨域请求,就是查看 request 请求头中是否有 Origin 属性

  24. if (CorsUtils.isCorsRequest(request)) {

  25. CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);

  26. CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);

  27. CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);

  28. executionChain = getCorsHandlerExecutionChain(request, executionChain, config);

  29. }

  30. return executionChain;

  31. }

进入 getHandlerInternal方法

所在类:org.springframework.web.servlet.handler. AbstractHandlerMethodMapping

  1. protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {

  2. // 从request对象中获取 URL,/common/query2

  3. String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);

  4. this.mappingRegistry.acquireReadLock();

  5. try {

  6. // 根据 URL 从映射关系中找到对应的 HandlerMethod 对象

  7. HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);

  8. // 执行beanFactory.getBean的过程,获取Controller实例

  9. return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);

  10. }

  11. finally {

  12. this.mappingRegistry.releaseReadLock();

  13. }

  14. }

::: warning 知识点

lookupHandlerMethod方法之所以可以从映射关系中拿到 HandlerMethod对象,是因为 AbstractHandlerMethodMapping类实现了 InitializingBean接口,在 afterPropertiesSet方法里建立好了映射关系。:::

进入 lookupHandlerMethod方法

所在类:org.springframework.web.servlet.handler. AbstractHandlerMethodMapping

  1. protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {

  2. List<Match> matches = new ArrayList<>();

  3. List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);

  4. if (directPathMatches != null) {

  5. // 匹配过程,是否符合 RequestMappingInfo 里的属性值

  6. addMatchingMappings(directPathMatches, matches, request);

  7. }

  8. if (matches.isEmpty()) {

  9. // No choice but to go through all mappings...

  10. addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);

  11. }

  12. if (!matches.isEmpty()) {

  13. Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));

  14. matches.sort(comparator);

  15. Match bestMatch = matches.get(0);

  16. if (matches.size() > 1) {

  17. if (logger.isTraceEnabled()) {

  18. logger.trace(matches.size() + " matching mappings: " + matches);

  19. }

  20. if (CorsUtils.isPreFlightRequest(request)) {

  21. return PREFLIGHT_AMBIGUOUS_MATCH;

  22. }

  23. Match secondBestMatch = matches.get(1);

  24. // 如果两个 RequestMappinginfo 什么都相同,报错

  25. if (comparator.compare(bestMatch, secondBestMatch) == 0) {

  26. Method m1 = bestMatch.handlerMethod.getMethod();

  27. Method m2 = secondBestMatch.handlerMethod.getMethod();

  28. String uri = request.getRequestURI();

  29. throw new IllegalStateException(

  30. "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");

  31. }

  32. }

  33. request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);

  34. handleMatch(bestMatch.mapping, lookupPath, request);

  35. return bestMatch.handlerMethod;

  36. }

  37. else {

  38. return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);

  39. }

  40. }

**::: warning 知识点 **

addMatchingMappings方法,主要一个匹配过程,匹配 @RequestMapping注解中的属性值是否满足

  1. /*

  2. * consumes:指定处理请求的提交内容类型(Content-Type),

  3. * 例如application/json, text/html;

  4. * produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;

  5. * params:指定request中必须包含某些参数值是,才让该方法处理。

  6. * headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。

  7. * */

  8. @RequestMapping(value = "/getUser",

  9. method = RequestMethod.GET,

  10. params = "username=jack",

  11. consumes = "application/json",

  12. produces = "application/json",

  13. headers = "Referer=http://www.xx.com/")

:::

返回 getHandler,进入 getHandlerExecutionChain方法

所在类:org.springframework.web.servlet.handler. AbstractHandlerMapping

  1. protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {

  2. // 如果没有获得则创建一个 HandlerExecutionChain

  3. HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?

  4. (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

  5. // 获取当前的请求地址:/user/xxx

  6. String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);

  7. // 在 HandlerExecutionChain 中添加拦截器

  8. // 遍历 SpringMVC 容器的所有拦截器

  9. for (HandlerInterceptor interceptor : this.adaptedInterceptors) {

  10. // 判断拦截器类型,如果是 MappedInterceptor 类型

  11. if (interceptor instanceof MappedInterceptor) {

  12. MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;

  13. // 则先匹配路径后再添加到执行链

  14. if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {

  15. chain.addInterceptor(mappedInterceptor.getInterceptor());

  16. }

  17. }

  18. else {

  19. // 否则直接添加到执行链

  20. chain.addInterceptor(interceptor);

  21. }

  22. }

  23. return chain;

  24. }

**::: warning 知识点 **

getHandlerExecutionChain中的 HandlerInterceptor拦截器是 SpringMVC中的, SpringAOP中的拦截器是 MethodInterceptor。:::

拿到当前请求对应的 handler后,

返回主流程,进入 getHandlerAdapter方法

所在类:org.springframework.web.servlet. DispatcherServlet

  1. /**

  2. * TODO : 根据 handlerMethod对象,找到合适的 HandlerAdapter对象,这里用到了策略模式

  3. */

  4. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {

  5. if (this.handlerAdapters != null) {

  6. for (HandlerAdapter adapter : this.handlerAdapters) {

  7. if (adapter.supports(handler)) {

  8. // 返回一个可以支持的HandlerAdapter 处理程序实例

  9. return adapter;

  10. }

  11. }

  12. }

  13. throw new ServletException("No adapter for handler [" + handler +

  14. "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");

  15. }

::: warning 知识点

HandlerAdapter 是什么HandlerAdapter是一个接口,充当自身与处理程序对象之间的桥梁,从而导致松散耦合设计。HandlerAdapter主要处理方法参数、相关注解、数据绑定、消息转换、返回值、调用视图解析器等。

  • RequestMappingHandlerMapping为当前的请求找到合适的处理程序方法。

  • RequestMappingHandlerAdapter执行这个处理程序方法,并为它提供反射调用所需要的参数。

HandlerAdapter UML 图

HandlerAdapter的4个实现类:

  1. SimpleServletHandlerAdapter: 适配实现 Servlet 接口的 Handler, 默认调用其 service方法

  2. SimpleControllerHandlerAdapter: 适配实现 Controller 接口的 Handler, 默认调用其 handleRequest 方法

  3. HttpRequestHandlerAdapter: 适配实现 HttpRequestHandler 接口的 Handler, 默认调用其 handleRequest 方法

  4. RequestMappingHandlerAdapter: 适配被 @RequestMapping注释的方式, 一般都是解析一个一个参数, 并且通过反射进行激活

HandlerAdapter 总结HandlerAdapterSpringMVC中扩展机制的非常好的一个体现,,通过 HandlerAdapter这种设计模式, DispatcherServlet 就可以支持任何格式的 Handler(这里的可以支持指在不改变 DispatcherServlet 的情况下),第二是 HandlerAdapter 基于不同 Handler实现不同实现类(策略模式),最后也是最重要的就是参数的解析与返回值的解析。

:::

::: danger 为什么要用HandlerAdapter适配器模式? 首先, Controller的定义有多种 ,一种是带 @Controller注解的, 还可以写一个 servlet当做 controller, 所以用适配器做适配,不同子类实现 HandlerAdapter接口,定义自己的业务逻辑,每个子类都是适配某一种类型的控制器,有了 HandlerAdapter,你只需要调用自己实现的 handle方法,屏蔽了不一致的细节,对用户来说直接找到对应的处理方法,无须关系哪个实现方法,否则只能在 DispatcherServlet里面通过 ifelse来处理了。:::

前置过滤器

返回主流程,进入 applyPreHandle方法,前置过滤器

所在类:org.springframework.web.servlet. DispatcherServlet

  1. /**

  2. * TODO :调用所有的 HandlerInterceptor 拦截器并调用其 preHandler方法

  3. */

  4. boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {

  5. // 获取所有的拦截器

  6. HandlerInterceptor[] interceptors = getInterceptors();

  7. if (!ObjectUtils.isEmpty(interceptors)) {

  8. for (int i = 0; i < interceptors.length; i++) {

  9. HandlerInterceptor interceptor = interceptors[i];

  10. // 分别调用拦截器的 preHandle 方法

  11. if (!interceptor.preHandle(request, response, this.handler)) {

  12. triggerAfterCompletion(request, response, null);

  13. return false;

  14. }

  15. // 如果失败,记录最后一次拦截器的位置,倒序释放

  16. this.interceptorIndex = i;

  17. }

  18. }

  19. return true;

  20. }

返回主流程,进入 handle方法,调用具体 Controller的方法

最终会进入 AbstractHandlerMethodAdapterhandle方法,

  1. public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)

  2. throws Exception {

  3. return handleInternal(request, response, (HandlerMethod) handler);

  4. }

进入 handleInternal方法,

所在类:org.springframework.web.servlet.mvc.method.annotation. RequestMappingHandlerAdapter

  1. protected ModelAndView handleInternal(HttpServletRequest request,

  2. HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

  3. ModelAndView mav;

  4. checkRequest(request);

  5. // Execute invokeHandlerMethod in synchronized block if required.

  6. if (this.synchronizeOnSession) {

  7. HttpSession session = request.getSession(false);

  8. if (session != null) {

  9. Object mutex = WebUtils.getSessionMutex(session);

  10. synchronized (mutex) {

  11. mav = invokeHandlerMethod(request, response, handlerMethod);

  12. }

  13. }

  14. else {

  15. // No HttpSession available -> no mutex necessary

  16. // 执行 HandlerMethod,返回 ModelAndView

  17. mav = invokeHandlerMethod(request, response, handlerMethod);

  18. }

  19. }

  20. else {

  21. // No synchronization on session demanded at all...

  22. // 执行 HandlerMethod,返回 ModelAndView

  23. mav = invokeHandlerMethod(request, response, handlerMethod);

  24. }

  25. if (!response.containsHeader(HEADER_CACHE_CONTROL)) {

  26. if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {

  27. applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);

  28. }

  29. else {

  30. prepareResponse(response);

  31. }

  32. }

  33. return mav;

  34. }

进入 invokeHandlerMethod方法,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值