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)

大家都在看

  • android系统中常见问题及分类

    版本: v0.2作者:河东希望日期:2022-7-6 对Android系统和应用来说,用户体验的基本目标是: 运行稳定 交互响应快 耗电少 启动快 所有违背这几个基本原则的问题,都…

    Linux 2023年6月7日
    095
  • [随记]-SpringMVC中的handler到底是什么东西

    HandlerMapping 初始化时候的 HandlerMapping 有,按顺序排列: requestMappingHandlerMapping beanNameHandler…

    Linux 2023年6月6日
    088
  • php+nginx环境搭建

    1、安装基础环境: yum -y install gcc bison bison-devel zlib-devel libmcrypt-devel mhash-devel open…

    Linux 2023年6月6日
    087
  • VR一体机如何退出FFBM(QFIL)

    前文介绍了通过fastboot命令擦除misc分区,从而退出FFBM的方法。这个方法比较简便,但有不灵的时候,fastboot erase misc命令执行失败,如下图所示。 er…

    Linux 2023年6月7日
    0107
  • 十、进程管理

    什么是进程?进程(Process)是一个程序在其自身的虚拟地址空间的一次执行活动。之所以要创建进程,就是为了使多个程序可以并发的执行,从而提高系统的资源利用率和吞吐量。简单来说进程…

    Linux 2023年6月7日
    0142
  • 安装 Ubuntu 20.04 之后要做的事(持续更新中)

    以 Ubuntu 20.04 LTS 为例,在安装完操作系统后,应进行以下操作,以方便我们日常的工作。 1. SSH 远程登录相关设置 安装 Ubuntu 操作系统之后,首先应该按…

    Linux 2023年5月27日
    090
  • Java的jinfo命令使用详解

    jinfo命令简介 jinfo(Java Virtual Machine Configuration Information)是JDK提供的一个可以实时查看Java虚拟机各种配置参…

    Linux 2023年5月27日
    0113
  • phpcmsv9 后台统计编辑发稿数量

    直切正题: 每个人,每个栏目,发稿数量统计 SELECT a.realname AS 姓名, c.catname AS 栏目名称, count(1) AS 发稿量FROM v9_n…

    Linux 2023年6月13日
    097
  • Github访问加速

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Linux 2023年6月8日
    085
  • ubuntu安装MySQL8.0.30

    ubuntu版本:Ubuntu 18.04.5 LTS MySQL版本:从8.0.25升级到8.0.30(2022年7月30号看,是最新版本) 升级目的:客户检测数据库服务器的my…

    Linux 2023年6月14日
    096
  • Linux基础和命令

    Linux的哲学思想 优势 一切都是一个文件。(包括硬件,文本,二进制,源代 码) 系统中拥有小型,单一用途的程序。(一个程序只负责 做好自己的本职工作) 当遇到复杂任务,通过不同…

    Linux 2023年6月6日
    094
  • c++ 11 是如何简化你的数据库访问接口的

    之前写过一篇文章专门分析了 c++ 模板编译过程中报的一个错误:《fatal error C1045: 编译器限制 : 链接规范嵌套太深 》,其中涉及到了 qtl —— 一个使用 …

    Linux 2023年6月6日
    099
  • AWS修改RDS时区

    查看 RDS 当前时区 默认情况下,AWS 的 RDS 采用的是 UTC 时间。而我们地区一般位于东八区,因此我们本地的时间是 UTC+8。 连接到 RDS 上,查询当前实例的时区…

    Linux 2023年6月7日
    0102
  • SSH升级版本–8.2p1

    前期准备 执行yum update openssh先升级下. 反正官方提供的这种升级是没问题的。如果之前手动编译操作过openssh的升级,变更了默认配置文件路径什么的请自行测试。…

    Linux 2023年6月8日
    094
  • redis的间隔性速度慢的问题

    php操作redis,偶尔间歇性很慢.查看redis日志发现:Asynchronous AOF fsync is taking too long (disk is busy?). …

    Linux 2023年5月28日
    087
  • Django中自定义管理器Manager用法

    Django中Manager用法 第一种 class create_user(models.Manager): def create(self, name, sex, age): …

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