springboot手把手教你0基础了解 请求映射原理 springboot第六期

小知识

  • HandlerMapping意思是处理器映射,把一个URL指定到一个Controller上

doGet的实现过程

在这里插入图片描述
HttpServlet生命了doGet方法
然后他的子类FrameworkServlet的doGet方法和dopost里面实际上执行的都是processRequest方法
在这里插入图片描述processRequest这个方法里面起主要作用的try里面的哪一行
在这里插入图片描述
也就是这里
在这里插入图片描述
但是点进去看这玩意是个抽象方法
在这里插入图片描述
这个方法的实现在它的子类里面 也就是下面这个
在这里插入图片描述
这个子类里面的doservice里面又很多东西 但是都不用看 里面起主要作用的是

 protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        this.logRequest(request);
        Map<String, Object> attributesSnapshot = null;
        if (WebUtils.isIncludeRequest(request)) {
            attributesSnapshot = new HashMap();
            Enumeration attrNames = request.getAttributeNames();

            label95:
            while(true) {
                String attrName;
                do {
                    if (!attrNames.hasMoreElements()) {
                        break label95;
                    }

                    attrName = (String)attrNames.nextElement();
                } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));

                attributesSnapshot.put(attrName, request.getAttribute(attrName));
            }
        }

        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
        if (this.flashMapManager != null) {
            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 {
            this.doDispatch(request, response);
        } finally {
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
                this.restoreAttributesAfterInclude(request, attributesSnapshot);
            }

        }

    }

这里起了主要作用

在这里插入图片描述

DispatcherServlet里面的 doDispatch() 是每个请求都会调用的方法

 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            try {
                ModelAndView mv = null;
                Object dispatchException = null;

                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }

                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }

                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }

                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }

                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }

        }
    }

细说doDispatch()

我们来看第一个干事的方法
在这里插入图片描述
检查是不是文件上传请求

在这里插入图片描述
如果是文件上传的话就进行一个转换

看当前请求是那个Handler(我们编写的Controller)去处理请求

在这里插入图片描述
发送个GET 请求

在这里插入图片描述
在这里插入图片描述
我们进入这个 getHandler

在这里插入图片描述
这个就是获取请求映射
在这里插入图片描述

handerMappings里面都保存了什么?

打断点看一下发送的请求
在这里插入图片描述
第一个存放了我们再controller存放的所有映射
后面四个都是系统给我们默认配置的 如果我们自定义的映射处理的话我们也会在这里面找到 关于自定义的我们以后再说

我们很容易就会看到在这里插入图片描述
这不就是我们的欢迎页面吗
来看一下
在这里插入图片描述
看一下路径设置
在这里插入图片描述
也就是说访问 / 会直接跳转到欢迎页面
在这里插入图片描述
也就是这页面
在这里插入图片描述
在这里插入图片描述
我们再来看这个
在这里插入图片描述
在这里插入图片描述
这个RequestMappingHandlerMapping保存了所有的@RequestMapping和handler的映射规则
那么它是怎么保存的?
springboot启动的时候会扫描所有的注解
比如说下面这些
在这里插入图片描述
然后把这些注解信息都保存到

在这里插入图片描述
这个里面
在这里插入图片描述
然后去找那个能处理这个请求
在这里插入图片描述
我们看看这里面都有什么信息

在这里插入图片描述
我们惊奇的看到 这里面写的都是我们自己写的映射
在这里插入图片描述

我们自己写的映射都在mappingLookup里面

这是我们自己写的映射
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
我们可以看到这都是一一对应的 当然我这里只截取了一部分

上面我们已经说过了 一个请求发过来要先遍历去寻找我们要用的controller
那么我们应该怎么去寻找?
这里面的继承关系很复杂 这里就不说了 到最里面实际干活的就是下面这个

getHandlerInternal 去寻找

在这里插入图片描述
这里先得到一个路径
在这里插入图片描述

然后再整一把🔒 避免并发查询的问题
在这里插入图片描述
这个有没有眼熟?
在这里插入图片描述
这不就是上面我们发现的放我们写的所有controller的那个地方吗?
在这里插入图片描述
我们再进入try里面
在这里插入图片描述
看看这个方法在干什么
在这里插入图片描述
看一下是怎么找的
现根据url找
在这里插入图片描述
看一下找到了什么
因为我们是用rest风格 所有找到了这四个
在这里插入图片描述
把所有找到的放到
这个集合里面

要是没找到就放个空
在这里插入图片描述
先把找到的符合规则的第一个给放进去
在这里插入图片描述
如果找到了很多

在这里插入图片描述
就各种排序 然后各种对比之后 就报个错
在这里插入图片描述
大概意思是你有几个方法能处理相同的请求
整体代码在下面

  if (!matches.isEmpty()) {
            AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
            if (matches.size() > 1) {
                Comparator<AbstractHandlerMethodMapping<T>.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
                matches.sort(comparator);
                bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace(matches.size() + " matching mappings: " + matches);
                }

                if (CorsUtils.isPreFlightRequest(request)) {
                    return PREFLIGHT_AMBIGUOUS_MATCH;
                }

                AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)matches.get(1);
                if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                    Method m1 = bestMatch.handlerMethod.getMethod();
                    Method m2 = secondBestMatch.handlerMethod.getMethod();
                    String uri = request.getRequestURI();
                    throw new IllegalStateException("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
                }
            }

总结

所有的请求映射都在HandlerMapping中。
● SpringBoot自动配置欢迎页的 WelcomePageHandlerMapping 。访问 /能访问到index.html;
● SpringBoot自动配置了默认 的 RequestMappingHandlerMapping
● 请求进来,挨个尝试所有的HandlerMapping看是否有请求信息。
○ 如果有就找到这个请求对应的handler
○ 如果没有就是下一个 HandlerMapping

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然!我将为您提供一步一步的Spring Boot入门指南。 1. 首先,确保您的开发环境已经配置好了Java和Maven。您可以在Oracle官方网站下载并安装Java Development Kit(JDK),同时确保您已经安装了Maven构建工具。 2. 打开您喜欢使用的集成开发环境(IDE),例如IntelliJ IDEA或Eclipse。创建一个新的Maven项目。 3. 在创建项目时,选择Spring Initializr作为项目模板。Spring Initializr是一个用于生成Spring Boot项目的在线工具,它可以帮助您设置项目的基本结构和依赖项。 4. 在Spring Initializr上,您可以选择项目的元数据,例如Group、Artifact和Spring Boot版本等。选择您喜欢的选项,并点击“Generate”按钮下载项目的压缩文件。 5. 解压缩下载的项目文件,并将其导入到您的IDE中。 6. 在IDE中打开`pom.xml`文件,这是Maven项目的配置文件。您可以在这里添加其他所需的依赖项。例如,如果您想创建一个基本的Web应用程序,可以添加以下依赖项: ```xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> ``` 7. 创建一个Java类作为您的应用程序的入口点。在IDE中,创建一个名为`DemoApplication.java`的类,并添加以下代码: ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 8. 创建一个简单的控制器来处理HTTP请求。在IDE中,创建一个名为`HelloController.java`的类,并添加以下代码: ```java import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/") public String hello() { return "Hello, Spring Boot!"; } } ``` 9. 运行应用程序。在IDE中,点击运行按钮或使用Maven命令`mvn spring-boot:run`来启动应用程序。 10. 打开Web浏览器,并访问`http://localhost:8080/`。您应该能够看到显示“Hello, Spring Boot!”的页面。 这只是一个简单的Spring Boot应用程序示例,您可以根据自己的需求进行扩展和定制。希望这个步骤指南能够帮助您开始使用Spring Boot!如果您有任何其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值