前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >写了一套优雅接口之后,领导让我给大家讲讲这背后的技术原理

写了一套优雅接口之后,领导让我给大家讲讲这背后的技术原理

作者头像
andyxh
发布2020-12-03 10:51:27
5090
发布2020-12-03 10:51:27
举报
文章被收录于专栏:程序通事

Hello,各位小伙伴们,早上好~

上周文章年轻人不讲武德,竟然重构出这么优雅后台 API 接口我们使用 @ControllerAdviceResponseBodyAdvice 重构后端的 API 接口,降低了复杂度,减少了重复代码,后续接口开发非常简洁优雅。

知其然而知其所以然,今天这篇文章来聊聊这个注解背后的原理,让我们彻底掌握这个注解,避免后续踩坑。

另外,有个小伙伴看完上篇文章,觉得这个注解的跟 Spring Interceptor 功能很类似,再加上之前还学习了 Servlet 体系 Filter 功能,不知道这几个有什么区别,感觉很混乱。

所以今天这篇文章下面两个部分出发,详细解释一下。

  1. @ControllerAdviceResponseBodyAdvice 注解原理
  2. FilterInterceptorResponseBodyAdvice 区别

欢迎关注我的公众号:程序通事,获得日常干货推送。如果您对我的专题内容感兴趣,也可以关注我的博客:studyidea.cn

从源码解析背后的原理

上篇文章中我们看到 ResponseBodyAdvice的子类使用 @ControllerAdvice注解,大家有没有好奇,如果我将@ControllerAdvice换成 @Controller 注解,还能达到上篇文章的效果吗?

感兴趣的小伙伴可以自己尝试下,这里小黑哥自己告诉大家结果了,实际测试结果是不行的。

那为什么一定要与@ControllerAdvice 搭配才会生效?

首先我们先查看一下 @ControllerAdvice 的源码:

可以看到这个注解上还存在一个我们非常熟悉的 @Component 注解。这里我们可以将 @ControllerAdvice 理解成@Component 子类,所以其修饰的类也会成为 Spring 中 Bean

ps:大家可以看下 @Controller/@Service/@Repository,其实也是这个原理。

Spring 容器初始化过程,如果扫描到 @ControllerAdvice 注解,将会将其生成一个 ControllerAdviceBean Bean。

这个过程代码主要位于 RequestMappingHandlerAdapter#initControllerAdviceCache:

这段代码主要分为两步:

第一步使用 ControllerAdviceBean#findAnnotatedBeans获取所有被 @ControllerAdvice修饰的类。

第二步将所有实现了ResponseBodyAdvice 接口的 Bean 放入到 requestResponseBodyAdviceBeans 集合中,后续将会使用该集合。

这就解释了为什么实现 ResponseBodyAdvice接口的子类一定要与@ControllerAdvice一起使用的原因了。

接下来我们来看下 ResponseBodyAdvice 的执行流程。

这里教给大家一个代码调试的小技巧,当我们不知道一个类在源码中如何被调用的时候,我们可以使用 IDEA 代码调试功能,然后查看代码调用栈。

如上面的所示,我们可以很清楚观察 ResponseBodyAdvice 调用关系。这里的类调用关系相对还是比较复杂,下面给大家简化一下。

前面的逻辑就不说了,就是 Spring MVC 通用流程。重点逻辑位于 RequestResponseBodyAdviceChain,我们具体看下源码:

嗯呐嗯呐,请忽略上图的 ③

其实逻辑非常简单,遍历所有的 ResponseBodyAdvice 的子类,首先调用其 supports判断是否支持,如果支持的调用的 beforeBodyWrite修改返回信息。

FilterInterceptorResponseBodyAdvice 区别

Filter属于 Servlet 组件,所有请求将会先进入 Filter ,判断通过之后才会在进入到真正的具体的请求中。

上图代表是用 Spring MVC 的一个 Web 项目,所有请求将会先进入到 Filter,通过之后才会进入到 SpringMVC 中最重要的组件 DispatchServlet

Interceptor 是 SpringMVC 的组件,它的作用实际上与 Filter类似, 只不过的它的作用是位于自定义的 Controller 前后。

不管是 Filter 还是 Interceptor,它们的作用方法域内只能拿到 ServletResponse 的参数,这个时候返回值已经被写入 ServletResponse,我们很难再去修改。

ResponseBodyAdvice作用时机位于写入之前,所以这个时候可以很容易拿到原值进行修改。

总结

SpringMVC 初始化的过程中,将会扫描所有带有 @ControllerAdvice注解的类,将其生成为 ControllerAdviceBean。如果这类刚好为 ResponseBodyAdvice接口的子类,Spring 将会为其单独保存起来,后续将会封装到的 RequestResponseBodyAdviceChain,使用责任链的模式对请求、响应进行处理。

最后我们解释了一下 FilterInterceptorResponseBodyAdvice区别,从作用范围上来讲:

代码语言:javascript
复制
Filter>Interceptor>ResponseBodyAdvice

但是前两者没办法修改返回值(时机太晚),只有后者才可以真正在返回值返回之前做到修改。

好了,今天文章就到这里了,下次我们分享一下如何写出优雅的 Dubbo 接口,下次见。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-12-02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 从源码解析背后的原理
  • Filter、Interceptor、ResponseBodyAdvice 区别
  • 总结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档