Spring中的Full模式和Lite模式,90%的开发都没搞明白
来自:
推荐一个程序员编程资料站:
http://cxyroad.com
副业赚钱专栏:https://xbt100.top
2024年IDEA最新激活方法
后台回复:激活码
CSDN免登录复制代码插件下载:
CSDN复制插件
以下是正文。
Spring中的Full模式和Lite模式,90%的开发都没搞明白
很多人天天写Spring,但如果你问一句:
@Configuration 为什么还能分 Full 模式和 Lite 模式?
不少人会直接愣住。
因为大多数人只知道 @Configuration 是配置类,却不知道它背后其实隐藏着两套运行机制。
而这两种模式,直接影响:
Bean 会不会重复创建
Spring 是否使用 CGLIB 动态代理
启动速度快不快
配置类性能高不高
微服务项目该怎么优化
今天这篇文章,小路就带你彻底搞懂 Spring 的 Full 模式 和 Lite 模式。
01 | @Configuration其实有两种运行方式
先看最普通的配置类:
@Configuration public class MyConfig { }默认情况下,它属于 Full 模式。
而如果这样写:
@Configuration(proxyBeanMethods = false) public class MyConfig { }那么它就变成了 Lite 模式。
很多人第一次看到 proxyBeanMethods 这个参数时,根本不知道它是干什么的。
实际上,它决定了:
Spring 是否对配置类进行 CGLIB 增强。
这也是 Full 和 Lite 最核心的区别。
02 | Full模式到底做了什么
默认情况下:
@Configuration等价于:
@Configuration(proxyBeanMethods = true)也就是说:
Spring 会通过 CGLIB 动态生成一个代理子类。
很多人不知道,真正放进 Spring 容器里的,其实已经不是你写的那个原始配置类了。
而是:
MyConfig$$EnhancerBySpringCGLIBSpring 会把你的配置类偷偷代理掉。
为什么要这么干?
核心目的就一个:
保证@Bean方法返回的对象永远是单例。
举个例子。
@Configuration public class AppConfig { @Bean public UserService userService() { return new UserService(orderService()); } @Bean public OrderService orderService() { return new OrderService(); } }这里有个关键点:
userService() 内部直接调用了 orderService()。
正常Java逻辑下:
orderService()就是普通方法调用。
意味着:
每调用一次都会 new 一个新对象。
但Spring不允许这样。
因为:
@Bean 默认是单例。
于是 Spring 的 CGLIB 代理就登场了。
它会拦截:
orderService()然后先去容器里检查:
有没有已经创建好的 Bean。
如果有:
直接返回容器里的对象。
而不是重新执行方法。
所以最终:
整个系统里只有一个 OrderService。
这就是 Full 模式最大的意义。
03 | Lite模式为什么越来越流行
再看 Lite 模式:
@Configuration(proxyBeanMethods = false)这时候 Spring 不会再创建 CGLIB 代理。
@Bean 方法也不会被拦截。
意味着:
orderService()就是一次普通Java调用。
调用一次:
创建一次对象。
这时候如果还存在配置类内部调用:
userService(orderService())那么:
OrderService 就可能被创建多次。
这也是 Lite 模式最大的风险。
但问题来了。
既然有风险。
为什么现在越来越多人开始用 Lite 模式?
因为:
它真的快。
尤其是在微服务时代。
很多项目:
Bean 数量巨大
配置类特别多
Spring Boot 自动配置越来越复杂
如果每个配置类都做 CGLIB 增强:
启动开销会明显增加。
而 Lite 模式直接省掉代理生成过程。
Spring 启动速度会更快。
内存占用也会更低。
所以现在很多官方自动配置:
都开始大量使用:
proxyBeanMethods = false尤其 Spring Boot 2.2 以后特别明显。
04 | 为什么Spring Boot官方开始偏向Lite模式
Spring 官方后来发现:
大多数配置类,其实根本不需要 Bean 方法互相调用。
很多配置类只是:
@Bean public A a() @Bean public B b()互相之间完全没关系。
这种情况下:
开启 CGLIB 代理纯属浪费。
于是 Spring Boot 官方开始大量优化:
能不用 Full 模式,就尽量不用。
因为对于现代微服务项目来说:
启动速度越来越重要。
容器化部署。
K8S弹性扩缩容。
Serverless冷启动。
都要求应用尽可能轻。
这也是为什么现在很多源码里你会看到:
@Configuration(proxyBeanMethods = false)甚至有些自动配置类:
已经明确建议关闭代理。
05 | Full模式和Lite模式到底该怎么选
很多人看到这里开始纠结:
那以后到底该用哪个?
其实原则非常简单。
如果配置类内部:
存在@Bean之间互相调用。
比如:
a() 调用了 b()那就必须使用 Full 模式。
否则可能出现:
Bean 被重复创建。
单例失效。
依赖错乱。
但如果:
@Bean 方法之间完全独立。
没有互相调用。
那么直接使用 Lite 模式更合适。
因为:
启动更快
内存更省
少了CGLIB代理
更适合微服务
现在很多高性能Spring项目:
都会主动关闭:
proxyBeanMethods这是近几年Spring生态一个非常明显的趋势。
06 | 一个很多人踩过的大坑
很多开发切到 Lite 模式后。
会突然发现:
单例失效了。
例如:
@Bean public A a() { return new A(b()); } @Bean public B b() { return new B(); }在 Lite 模式下:
b()不会从容器获取。
而是真正执行方法。
于是:
new B()被执行多次。
最终:
A 里的 B
和容器里的 B
根本不是同一个对象。
这个坑很多人线上都踩过。
所以记住一句话:
Lite 模式下。
@Bean 方法之间尽量不要直接调用。
正确做法应该是:
通过参数注入。
例如:
@Bean public A a(B b) { return new A(b); }这样 Spring 会自动从容器里拿 Bean。
既不会重复创建。
又能安全使用 Lite 模式。
07 | 现在真正厉害的Spring开发,早就开始主动优化配置类了
以前很多人写 Spring:
根本不管配置类性能。
反正能跑就行。
但现在不一样了。
微服务越来越重。
自动配置越来越多。
启动时间已经变成核心指标。
尤其云原生时代:
启动慢。
就意味着:
扩容慢。
恢复慢。
成本更高。
所以现在很多大厂:
已经开始专门治理 Spring 配置类。
能 Lite 的绝不 Full。
能避免代理的绝不增强。
因为大型系统里:
几百个配置类叠加起来。
差距真的会越来越明显。
这也是为什么:
真正懂 Spring 底层的人。
看到一个:
@Configuration第一反应不是配置类。
而是:
这里到底需不需要 CGLIB 代理。
<END>
推荐阅读:
副业赚钱推荐:让你的时间开始变现!
免费体验AI图片生成,就在 Image Generator Hub!
程序员在线工具站:cxytools.com 推荐一个自己写的工具站:https://cxytools.com,专为程序员设计,包括时间日期、 JSON处理、SQL格式化、随机字符串生成、UUID生成、文本Hash...等功能,提升开发效 率。 ⬇戳阅读原文直达! 朕已阅
