Spring源码学习---如何处理HTTP请求

        在用Spring Boot开发时,要让一个类具有处理HTTP请求的能力,很多人都知道,加两个注解:

        @RestController

        @RequestMapping

        那么,为什么加了这两个注解,类就可以拥有这个能力了呢,Spring框架背后做了什么事情?这就涉及到两个知识点:注解和反射。我们在创建自定义注解的时候,通常都会使用AOP(面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术)去拦截指定包路径下的类,然后利用反射去扫描类或方法上的注解进行我们自定义注解的具体逻辑处理,同样,Sping也是这样做的(注意:SpringMVC和Spring是不一样的东西!),这样做的好处有如下几点:

        1. 简化配置

        2. 增强可读性

        3. 提高可复用性

        4. 提升可维护性

        5. 增加易变更性

        下面来跟一下源码的大致流程来了解下。

        从源码提供的单元测试开始调试跟踪吧,如下这个单元测试: 

       (org.springframework.web.servlet.handler.HandlerMethodMappingTests)

        Spring源码学习---如何处理HTTP请求_第1张图片

       Build的时候出现如下错误:

       Spring源码学习---如何处理HTTP请求_第2张图片 

       修改项目的仓库配置,增加一项即可:

       Spring源码学习---如何处理HTTP请求_第3张图片

       先运行单元测试,没问题再细看源码。

       运行时发生如下错误,更新Kotlin版本插件即可:

        Spring源码学习---如何处理HTTP请求_第4张图片

        注意,单元测试需要执行命令行,直接IDE点击绿色三角图标运行是不行的:

        

        好,单元测试运行成功,开始看看源码。

        在单元测试了里,定义了一个控制器,如下:

         Spring源码学习---如何处理HTTP请求_第5张图片

         注解@Controller说明了这个类可以处理HTTP请求,@RequestMapping声明该控制器类由两个方法分别处理不同的URL请求。         

         MyHandlerMethodMapping继承于抽象基类AbstractHandlerMethodMapping:

         Spring源码学习---如何处理HTTP请求_第6张图片

         从注释信息可以看到,这是一个定义了请求和实现方法对应关系的抽象基类,其类继承关系如下图所示:

        Spring源码学习---如何处理HTTP请求_第7张图片

         在这个类里通过调用方法initHandlerMethods()来初始化请求和方法的关联,其流程如下:

         1. 扫描,获取ApplicationContext下所有的bean的名字

         2. 循环所有bean,有bean名字得到其类型Class后,判断是否是handler(isHandler(...)是抽象方法,由该单元测试的静态类

MyHandlerMethodMapping实现,因为是单元测试,仅仅返回true),实际实现如下:

               org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

               Spring源码学习---如何处理HTTP请求_第8张图片

               明明显看到,就是在扫面加了@Controller或@RequestMapping的bean,加了就是控制器。

         3. 如果bean是控制器,则扫描里面用来响应http请求的方法: detectHandlerMethods(beanName),它就是通过反射拿到方法,然后注册(即保存)到Map中:

         Spring源码学习---如何处理HTTP请求_第9张图片

              Spring源码学习---如何处理HTTP请求_第10张图片

         4. 最后是请求方法的初始化,这里没实现。

        从流程上可以看到,springmvc对http的请求处理就是,收到一个http请求,截取到url路径,然后到mappingregistry里找其对应的处理方法,找到就进行处理,没有就是404了。

        了解了上面的流程,单元测试就好理解了,主要是验证逻辑的正确性,可以自行学习。

你可能感兴趣的:(Spring)