默认情况下,Spring应用在启动时会立即初始化所有被@Component等注解标识的Bean。这意味着Spring会为每个Bean创建实例,消耗内存与CPU资源,以保证启动后立即可用。然而,有些Bean可能使用频率很低,但其初始化成本却很高。对于这类Bean,我们希望采用“按需创建”的策略,即懒加载(Lazy Loading)。
1. 验证Bean的立即初始化
我们可以通过一个简单的实验来观察Bean的初始化时机。在每个Coach接口实现类的构造方法中,添加一行日志输出:

启动程序后,观察控制台日志:

可以看到,定义的4个Coach实现类在应用启动过程中就已经全部完成了初始化。
2. 使用@Lazy实现懒加载
懒加载意味着Bean不会被立即创建,只有在以下两种情况发生时才会被初始化:
通过在类上添加@Lazy注解,即可实现该类的懒加载。我们以上述Demo为例,为TrackCoach类添加@Lazy注解:
@Lazy
@Component
public class TrackCoach implements Coach {
public TrackCoach() {
System.out.println("In constructor: " + getClass().getSimpleName());
}
}
注意,当前Controller中仅依赖并使用了CricketCoach:
@RestController
public class FunRestController {
private Coach coach;
@Autowired
public FunRestController(@Qualifier(“cricketCoach”) Coach coach) {
this.coach = coach;
}
@GetMapping(“/workout”)
public String getDailyWorkout() {
return coach.getDailyWorkout();
}
}
由于整个应用在启动时没有对TrackCoach的依赖,因此其构造方法不会执行:

3. 配置全局懒加载
如果需要对大多数Bean启用懒加载,为每个类单独添加@Lazy注解显然过于繁琐。Spring Boot提供了全局配置的方式,只需在application.properties或application.yml配置文件中添加:
spring.main.lazy-initialization=true
启用全局懒加载后再次启动应用,会发现所有Coach实现类的构造函数均未执行。此时,包括FunRestController在内的所有Bean都变为懒加载。只有当请求/workout接口时,才会触发FunRestController及其依赖的CricketCoach的初始化。我们可以在FunRestController的构造函数中添加日志进行验证:
@Autowired
public FunRestController(@Qualifier(“cricketCoach”) Coach coach) {
System.out.println(“In constructor: ” + getClass().getSimpleName());
this.coach = coach;
}
通过浏览器访问/workout接口,控制台输出如下:

需要注意的是,当存在依赖注入时,Bean的初始化遵循依赖顺序:优先初始化被依赖的Bean,再初始化自身。
4. 懒加载的优缺点与建议
优点:
- 节省资源:仅在需要时才创建对象,减少不必要的内存占用和CPU消耗。
- 加速启动:对于包含大量组件的应用,能显著缩短应用启动时间。
缺点:
- 延迟发现问题:如
@RestController等Web组件,直到首个请求到来时才会初始化,可能将配置错误等问题延迟到运行时才发现。
- 增加请求延迟:首个请求需要等待Bean初始化,可能导致响应时间变长。
综上所述,懒加载是一把双刃剑。正因如此,Spring Boot默认关闭了全局懒加载配置。建议的开发实践是:非必要不开启全局配置,而是针对特定的、初始化成本高且使用不频繁的Bean,有选择地使用@Lazy注解进行优化。