type
status
date
slug
summary
tags
category
icon
password
Property
Nov 8, 2024 04:59 PM
我认为短期内要想快速学习理解Spring,很重要的一定要具备的一点潜质:多问问为什么
Spring中的知识铺垫
阅读本文,需要知道的一点,想必也是赘述的一些内容,大佬们可以自行跳过,我为不熟悉Spring的朋友介绍一下。Spring作为一款老牌的强大的OOP思想的容器框架,他有着自己的一套管理Bean的方式,对于Spring框架,最为人所熟知的莫过于它的IOC容器与AOP代理,这也是最基本的。那么对于那些被Spring所管理的Bean而言,他们也有着自己的生命周期。Spring正是通过基于良好的OOP思想,为每一个它所管理的Bean构建了全生命周期链路…知道了这些,那么看下面的内容就不会头疼了哈。
SpringCloud的一些细节
这里用一个回顾SpringCloud基础中发现的一个细节来讲讲,Spring设计的精妙。
在微服务中,我们经常与分布式集群打交道,那么对于RPC请求的时候负载均衡策略因该是耳熟能详了,这里我们不讲广为人知的负载均衡算法,而是看看发起请求的客户端。
经常可以看到,在SpringCloud的一些早期项目中,在没有引入OpenFeign之前,发起RPC请求,我们会看到有RestTemplate与WebClient这两种原生的选择。通常,我们是这么使用的
对RestTemplate的管理
对WebFlux中WebClient的管理
通过被Spring管理后,可以在其他上下文的地方引入Bean进行调用。我们可以看到,对于RestTempalte我们是直接将new出来的新建的对象交由Spring管理,而WebClient则是通过创建WebClient的Builder,最后将Builder对象交由Spring管理,如果你仔细分析,按照形式主义的思想去看,很容易看出来,为什么这里不能直接给New,新创建的WebClient对象给到Spring管理呢?而是给出一个Builder给到Spring。
这时候,重点来了,我们反思一下,为什么要提供Builder给Spring,回忆一下,Spring管理Bean核心是什么,是为每一个Bean设计了自己的生命周期,通过代理的方式去增强Bean,那么答案呼之欲出了,Spring要管理Bean,增强Bean就必须遵守Spring的规则,Spring只能通过:
(1)CGLib增强字节码增强(需要继承类);
(2)基于JDK动态代理增强(需要实现接口);
而在看WebClient,WebClient被设计为一个响应式的、非阻塞的Web客户端,它的构建过程是通过WebClient.Builder完成的。一旦构建完成,WebClient实例就不应该被修改,这种不可变性使得它不适合被Spring通过动态代理增强,所以在回过头来就能想清楚原因了:
(1)能被CGLib增强字节码增强吗?
CGLIB是通过创建目标类的子类来实现代理的,这意味着它需要目标类不是final的,并且不包含final的方法。CGLIB通过字节码生成技术在运行时动态创建代理类。对于WebClient来说,他在调用了Build之后,是最终类,无法再修改,因此Spring Cloud的负载均衡器是基于WebClient.Builder进行配置的,而不能在WebClient实例上。
(2)能基于JDK动态代理来实现增强吗?
JDK动态代理是基于接口的代理机制,它只能代理实现了接口的类。这是因为JDK动态代理是通过创建一个实现了一组接口的代理类来实现的。由于WebClient是一个具体的类,不是一个接口,因此它不能被JDK动态代理
所以在注入WebClient的时候为什么要给Spring它的Builder而不是直接给出WebClient对象,清楚了吧,这就是融会贯通。
好,不迷糊,为了进一步验证是这个原因,再来看RestTemplate,这是JDK17底下Spring中RestTemplate的实现。可以很清晰的发现,RestTemplate继承了
InterceptingHttpAccessor
类,实现了
RestOperations
接口。
•
InterceptingHttpAccessor
是一个抽象类,它继承自 HttpAccessor
并添加了对请求拦截器的支持。这个类允许配置请求拦截器,这些拦截器可以在请求发送前后执行自定义逻辑。
•
RestOperations
接口定义了一组基本的REST操作,如GET、POST、PUT、DELETE等。RestTemplate
是这个接口的唯一实现,这意味着它提供了这些REST操作的具体实现。这种设计使得
RestTemplate
既可以利用接口实现JDK动态代理,又可以通过继承类实现CGLIB字节码增强。
- JDK动态代理:由于
RestTemplate
实现了RestOperations
接口,它可以被JDK动态代理。JDK动态代理通过创建一个实现了相同接口的代理类来实现,这个代理类在运行时动态生成,可以拦截对应接口方法的调用。
- CGLIB字节码增强:尽管
RestTemplate
继承了InterceptingHttpAccessor
类,但由于CGLIB可以代理没有实现接口的类(通过创建目标类的子类),RestTemplate
也可以通过CGLIB进行增强。CGLIB不要求目标类实现接口,而是通过生成目标类的子类来实现代理。
总结
这就是Spring的精妙设计。
参考文章
致谢:
欢迎各位大佬们赐教,子曰:三人行,必有我师焉
- 作者:fntp
- 链接:https://polofox.com/article/java-BITE-02
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章