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

38次阅读

共计 2244 个字符,预计需要花费 6 分钟才能阅读完成。

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

上周文章年轻人不讲武德,居然重构出这么优雅后盾 API 接口咱们应用 @ControllerAdviceResponseBodyAdvice 重构后端的 API 接口,升高了复杂度,缩小了反复代码,后续接口开发十分简洁优雅。

知其然而知其所以然,明天这篇文章来聊聊这个注解背地的原理,让咱们彻底把握这个注解,防止后续踩坑。

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

所以明天这篇文章上面两个局部登程,具体解释一下。

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

从源码解析背地的原理

上篇文章中咱们看到 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区别,从作用范畴上来讲:

Filter>Interceptor>ResponseBodyAdvice

然而前两者没方法批改返回值(机会太晚),只有后者才能够真正在返回值返回之前做到批改。

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

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

正文完
 0