@Lazy
@Lazy 是 Spring 框架中的一个注解,用于控制 Bean 的加载时机,实现延迟初始化(Lazy Initialization)。它的核心作用是:推迟 Bean 的创建,直到第一次被实际使用时才初始化,而不是在 Spring 容器启动时就立即创建
- 作用于 @Bean 方法
@ConfigurationpublicclassAppConfig{@Bean@Lazy// 只有当其他 Bean 注入或调用此方法时才会创建publicExpensiveServiceexpensiveService(){returnnewExpensiveService();// 假设初始化很耗时}}- 作用于 @Component 或其派生注解(如 @Service, @Repository)
@Service@Lazy// 整个类的 Bean 延迟初始化publicclassUserService{publicUserService(){System.out.println("UserService 被创建了");}}- 作用于依赖注入点(如构造函数、字段)
@ServicepublicclassOrderService{privatefinalUserServiceuserService;// 只有当 OrderService 被使用时,才会初始化 UserServicepublicOrderService(@LazyUserServiceuserService){this.userService=userService;}}| 场景 | 说明 |
|---|---|
| 减少启动时间 | 避免在应用启动时初始化所有 Bean(尤其是重量级组件)。 |
| 解决循环依赖 | 在某些复杂的循环依赖场景中,@Lazy可作为临时解决方案(但应优先重构代码)。 |
| 按需加载资源 | 如数据库连接池、缓存客户端等,只在首次调用时初始化。 |
什么算“第一次被实际使用”?
| 场景 | 是否触发初始化 |
|---|---|
@Autowired声明字段(无@Lazy) | ❌ 不会(但若宿主 Bean 非懒加载,则随宿主一起初始化) |
@Autowired @Lazy声明字段 | ❌ 声明时不触发,✅ 首次调用方法时触发 |
applicationContext.getBean() | ✅ 立即触发 |
| 被非懒加载的 Bean 直接依赖 | ✅ 随依赖方初始化时触发 |
| 仅被定义但从未引用 | ❌ 永远不会初始化 |
@Lazy 推迟初始化的“第一次使用”,确实包括通过 @Autowired 或 @Resource 注入后的首次方法调用。
特别是当你在注入点上加上 @Lazy 时,Spring 会使用代理实现真正的“按需初始化”。
你可以在 注入点 上加 @Lazy,这是 Spring 提供的一种高级技巧:
@Lazy@ServicepublicclassRecommendationService{...}@ServicepublicclassUserService{@Autowired@LazyprivateRecommendationServicerecommendationService;}Spring 会给 recommendationService 字段注入一个 动态代理对象(不是真实实例)。
只有当你第一次调用 recommendationService 的任意方法时,Spring 才会:
1.去容器中查找/创建真正的 RecommendationService Bean;
2. 将后续调用委托给真实对象。
如果在Bean上加了@Lazy , 在注入点里没加会发生什么?
@Lazy@ServicepublicclassRecommendationService{...}@ServicepublicclassUserService{@AutowiredprivateRecommendationServicerecommendationService;// ← 无 @Lazy}- 虽然 RecommendationService 是懒加载的,
- 但由于它被 UserService 直接依赖(且 UserService 不是懒加载的),
- Spring 在创建 UserService 时 仍然需要一个可用的 RecommendationService 实例来完成注入,
- 所以 RecommendationService 会在 UserService 初始化时被提前创建(即启动时)。