springBoot 获取注解参数的原理

  • 判断每个参数带有注解是哪个,是否存在相应的解析器

  • 寻找合适的处理适配器

 DispatcherServlet中的
     doDispatch方法
        // Determine handler adapter for the current request.

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

springBoot 获取注解参数的原理
  • 寻找可以处理相应注解的处理器
第一步
DispatcherServlet中的
    doDispatch方法
        // Actually invoke the handler.

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

第二步
RequestMappingHandlerAdapter中的
    handleInternal方法
        // No synchronization on session demanded at all...
            mav = invokeHandlerMethod(request, response, handlerMethod);
    invokeHandlerMethod方法
        invocableMethod.invokeAndHandle(webRequest, mavContainer);

第三步
ServletInvocableHandlerMethod中的
    invokeAndHandle方法
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);

第四步
InvocableHandlerMethod类中的
    invokeForRequest方法
        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);//获取请求的参数

第五步
InvocableHandlerMethod类中的
    getMethodArgumentValues方法
            if (!this.resolvers.supportsParameter(parameter)) {//寻找处理相关注解的处理器,并保存到缓存中 supportsParameter(parameter)从这里进入的
                throw new IllegalStateException(formatArgumentError(parameter,                              "No suitable resolver"));
            }
            try {
            args[i] = this.resolvers.resolveArgument(parameter,     mavContainer,                   request, this.dataBinderFactory);
        }

第六步
HandlerMethodArgumentResolverComposite类中的
        @Nullable
        private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter                                                       parameter) {
            HandlerMethodArgumentResolver result =
                this.argumentResolverCache.get(parameter);//从缓存中获取,开始肯定没有
            if (result == null) {
                //增强for循环中选择合适的处理器  27个
                for (HandlerMethodArgumentResolver resolver :
                     this.argumentResolvers) {
                    if (resolver.supportsParameter(parameter)) {
                        result = resolver;
                        //保存到缓存中
                        this.argumentResolverCache.put(parameter, result);
                        break;
                    }
                }
            }
            return result;
        }

springBoot 获取注解参数的原理
  • 通过注解处理器获取参数
第一步
InvocableHandlerMethod类中的
    getMethodArgumentValues方法

        try {
            args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); //真正开始获取参数
        }

第二步
HandlerMethodArgumentResolverComposite类中的
    resolveArgument方法中
        //获取参数对应注解的处理器
        HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
    getArgumentResolver方法中
    //从缓存中获取,由于开始的之前往缓存中存入了,所以现在可以直接拿,如果没有下面还有可以循环寻找
        HandlerMethodArgumentResolver result =
                        this.argumentResolverCache.get(parameter);

AbstractNamedValueMethodArgumentResolver类中的
    resolveArgument方法
        Object resolvedName =
            resolveEmbeddedValuesAndExpressions(namedValueInfo.name);//获取参数名
        Object arg = resolveName(resolvedName.toString(),
                                 nestedParameter, webRequest);//获取参数值

//具体怎么获取
PathVariableMethodArgumentResolver类中的
    resolveName方法
    protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
    Map uriTemplateVars = (Map) request.getAttribute(//直接从request请求域中获取
        HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
    return (uriTemplateVars != null ? uriTemplateVars.get(name) : null);//在通过参数名称确定是哪一个
}
  • 获取参数完成后,会调用InvocableHandlerMethod来中的doInvoke方法继续反射调用方法
InvocableHandlerMethod类中的
    doInvoke方法
        return method.invoke(getBean(), args);

Original: https://www.cnblogs.com/shuisanya/p/16630369.html
Author: 水三丫
Title: springBoot 获取注解参数的原理

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/581448/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Windows 是最安全的操作系统

    建了一个用户交流群,我在群里说:”Windows 是最安全的操作系统。” 立刻引发了很多有意思的观点。我在群里一个人说不过大家,先篇文章把自己的论点罗列一下…

    Linux 2023年6月14日
    078
  • Linux 下重启 PHP 服务、nginx 服务

    一、重启 PHP 服务 service php-fpm start 开启 service php-fpm stop 停止 service php-fpm restart 重启 二、…

    Linux 2023年6月13日
    071
  • Cisco GNS3教程,GNS3搭建IPv6 6rd环境,Linux 配置 IPv6 6rd详析

    Cisco GNS3 IPv6 6rd实验 1、回顾 前文:https://www.cnblogs.com/kingpop/p/14054321.html在描述Cisco GNS3…

    Linux 2023年6月6日
    087
  • kafka能做什么?kafka集群配置 (卡夫卡 大数据)

    什么是Kafka 官网介绍: 几个概念: 详细介绍 : 操作kafka: kafka集群 消息测试 问题检测 什么是Kafka 官网介绍: ApacheKafka®是一个分布式流媒…

    Linux 2023年6月7日
    0109
  • 从磁盘删除Ubuntu出现的问题

    问题描述:Win10+Ubuntu双系统,利用磁盘管理工具删除了Ubuntu占用的磁盘,导致开机直接进入Grub界面,并且启动项仍有Ubuntu。 问题解决: 开机进入BIOS或启…

    Linux 2023年6月14日
    088
  • OpenSSL测试-SM3

    任务详情 在openEuler(推荐)或Ubuntu或Windows(不推荐)中完成下面任务 使用OpenSSL的命令计算你的8位学号的摘要值(SM3),提交截图(5’…

    Linux 2023年6月8日
    095
  • 迭代

    1.迭代的概念: 迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次”迭代”,而每一次迭代得到的结果会作为下一次迭代的…

    Linux 2023年6月8日
    099
  • Linux常用文件权限命令详解

    pwd pwd命令用于获取当前工作目录的绝对路径。 使用示例: pwd 效果如下图: cd cd命令用于切换工作目录。 使用示例: cd 万&#x73…

    Linux 2023年5月27日
    095
  • Fabric2.2中的Raft共识模块源码分析

    引言 Hyperledger Fabric是当前比较流行的一种联盟链系统,它隶属于Linux基金会在2015年创建的超级账本项目且是这个项目最重要的一个子项目。目前,与Hyperl…

    Linux 2023年6月7日
    069
  • Linux 配置Java环境变量

    前言:请各大网友尊重本人原创知识分享,谨记本人博客: 南国以南i 注:目前,您需要在官网下载时登录。在此共享帐户以方便下载。 [En] Note: at present, you …

    Linux 2023年5月27日
    091
  • 微服务与领域驱动设计,架构实践总结

    怎样的架构才能配得上造到飞起的变化? 一、软件复杂性 1、复杂原因 如果软件系统存在持续的迭代周期,那么其中业务、技术、架构的复杂性都会直线拉升,其相应的开发难度也会提高,可以用一…

    Linux 2023年6月14日
    056
  • 进程与fork

    进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程…

    Linux 2023年6月7日
    090
  • Git基本使用命令

    Git配置 Git最小配置 配置全局账户,该账户对所有Git仓库都有效 git config –global user.name ‘账&#x6237…

    Linux 2023年6月13日
    070
  • nand

    nand flash裸机编程第001节_NAND_FLASH操作原理第002节_NandFlash时序及初始化第003节_NandFlash的芯片id读取第004节_NandFla…

    Linux 2023年6月13日
    067
  • PyTorch介绍-保存和加载模型

    本节我们将会看到如何保存模型状态、加载和运行模型预测 import torch import torchvision.models as models 保存和加载模型权重 PyTo…

    Linux 2023年6月14日
    090
  • Redis缓存三大问题解析,看完保你面试能造火箭,工作能拧螺丝。

    前言 日常的开发中,无不都是使用数据库来进行数据的存储,由于一般的系统任务中通常不会存在高并发的情况,所以这样看起来并没有什么问题。 面试10家公司,收获9个offer,2020年…

    Linux 2023年5月28日
    084
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球