品牌型号:联想ThinkPad X1
系统:Windows10家庭版
软件版本:Spring 5.3.7
我们用Spring开发久了,会发现确实用着很顺手,但如果真要解释某些功能或者原理,反而说不明白,比如说Bean的加载时机和作用域就是典型的例子。懒加载这个词大家都不陌生,但Spring Bean到底默认是不是懒加载呢?估计有很多人都没去认真验证过,只是凭着感觉在答。说到单例就更有意思了,几乎所有人都知道Spring Bean默认是单例,但为什么是单例,这个设计背后的考量是什么?下面就给大家介绍一下Spring Bean默认是懒加载吗,Spring Bean为什么默认是单例的相关内容。
一、Spring Bean默认是懒加载吗
Spring Bean默认不是懒加载的,在容器启动的时候,Bean就已经被创建好了,不需要等到第一次使用才初始化,ApplicationContext 在启动阶段会扫描所有配置,把符合条件的Bean统一实例化并注入依赖,整个过程在应用跑起来之前就完成了。

这个机制有个很实际的好处,如果某个Bean的配置有问题或者依赖注入出了错,启动阶段直接就报了,不会等到运行中某个功能被触发才暴露,这对于线上服务来说,启动时报错比运行时报错要好处理得多。

那懒加载是什么情况?加上@Lazy 注解之后,对应的Bean会推迟到第一次被调用时才初始化,这种方式适合一些初始化成本比较高、但不一定每次都用到的Bean,可以在一定程度上缩短应用的启动时间。不过副作用也有,问题被推迟暴露,排查起来反而麻烦。

二、Spring Bean为什么默认是单例
Spring Bean默认确实是单例,整个容器生命周期内,同一个Bean只会创建一次,后续每次注入拿到的都是同一个实例。为什么这样设计?原因很直接,就是为了提高性能,大家都知道对象的创建和销毁是有开销的,如果每次用到某个Bean都重新实例化一遍,在请求量大的场景下,这部分开销会非常可观。单例的方式让对象只初始化一次,后续复用,既省了内存,也减少了GC的压力。

而且Spring管理Bean的方式本身就适合单例,容器负责创建、注入依赖、管理生命周期,这套流程如果每次请求都走一遍,成本很高,意义也不大。大多数业务组件,比如Service、Repository、Controller,本身就是无状态的,里面不存用户相关的数据,同一个实例被多个地方共用完全没有问题。

这里有个注意点值得给大家提下,单例是安全的前提是Bean本身无状态,如果在单例 Bean 里定义了成员变量来存储请求级别的数据,多线程环境下就会出现数据混乱的问题,这是使用单例时最常见的一类错误。

以上就是Spring Bean默认是懒加载吗,Spring Bean为什么默认是单例的全部内容了。懒加载和单例这两个问题,并不难理解。Spring Bean默认饿加载是为了让问题早点暴露,而默认是单例是为了减少开销、提升复用效率,背后都是同一套思路,在合理的默认行为上做设计,让开发者不需要额外配置也能跑得稳。当然默认行为不是一成不变的,懒加载可以按需开启,作用域也可以根据场景切换,关键是理解每种选择背后的代价。把这两个问题搞清楚,对Spring容器的运作方式会有更具体的认识。