一、核心功能与作用
@Lazy
注解是 Spring 框架中用于延迟 Bean 初始化的核心工具,通过将 Bean 的创建推迟到首次使用时,优化资源利用和启动性能。其核心功能包括:
- 延迟初始化
默认情况下,Spring 在容器启动时立即初始化所有单例 Bean。@Lazy
可延迟初始化,减少启动时间,尤其适用于资源密集型或低频使用的 Bean。 - 解决循环依赖
当两个 Bean 互相依赖时,@Lazy
可打破初始化顺序,避免启动时报错。例如,通过将依赖标记为延迟加载,Spring 容器允许代理对象先行注入,实际 Bean 在首次使用时创建。 - 优化资源占用
适用于初始化耗时或占用大量内存的 Bean(如数据库连接池、大数据处理服务),避免启动时不必要的资源消耗。
二、使用场景
资源密集型 Bean
如邮件服务、大数据处理模块,避免启动时加载占用资源。
示例:
@Service @Lazy public class BigDataServiceImpl { ... }
。
低频访问的组件
- 如仅在特定用户操作时触发的服务(如报表生成)。
循环依赖场景
当两个 Bean 互相依赖时,对其中一个添加
@Lazy
注解:@Component public class PersonConfig { public PersonConfig(@Lazy UserConfig userConfig) { ... } }
按需加载配置
- 如仅在特定环境或条件下需要初始化的组件,结合
@Profile
或@Conditional
使用。
- 如仅在特定环境或条件下需要初始化的组件,结合
三、使用方法
@Lazy
支持多种作用域和注入方式:
- 类级别
延迟该类的所有单例 Bean 初始化:@Configuration @Lazy public class AppConfig { @Bean public MyBean myBean() { ... } // 延迟初始化 }
- 方法级别
标记特定@Bean
方法为延迟加载:@Bean @Lazy public DataSource dataSource() { ... }
- 字段注入
在@Autowired
等注入点使用,延迟依赖的初始化:@Autowired @Lazy private EmailService emailService;
- 构造函数参数
延迟依赖 Bean 的初始化:public class ServiceA { public ServiceA(@Lazy ServiceB serviceB) { ... } }
四、注意事项
- 仅适用于单例 Bean
原型(Prototype)作用域的 Bean 每次请求都会创建新实例,无需延迟。 - 线程安全性
延迟初始化的单例 Bean 需确保线程安全,避免并发问题。 - 默认值控制
@Lazy
的value
属性默认为true
(延迟),设为false
可强制立即初始化。 - 避免滥用
滥用可能导致依赖关系复杂化,或首次调用时性能下降。
五、底层原理
- 代理机制
Spring 通过动态代理(CGLIB 或 JDK 代理)创建延迟 Bean 的占位符。首次调用时触发实际 Bean 的初始化。 - 依赖注入处理
在注入点使用@Lazy
时,Spring 注入代理对象而非真实实例,实际调用时代理对象触发 Bean 的创建。 - 生命周期管理
延迟初始化的 Bean 仍遵循 Spring 生命周期回调(如@PostConstruct
),但仅在首次使用时执行。
六、实际案例
延迟邮件服务初始化
@Service @Lazy public class EmailServiceImpl implements EmailService { @PostConstruct public void init() { System.out.println("邮件服务初始化完成!"); } }
- 仅在首次发送邮件时初始化。
解决循环依赖
@Component public class UserConfig { private final PersonConfig personConfig; public UserConfig(@Lazy PersonConfig personConfig) { this.personConfig = personConfig; } }
- 避免
UserConfig
和PersonConfig
的循环依赖报错。
- 避免
总结
@Lazy
通过灵活的延迟加载机制,显著优化了 Spring 应用的启动性能和资源利用率。合理使用需结合具体场景,权衡初始化时机与依赖关系复杂度。对于复杂项目,建议通过日志监控延迟 Bean 的初始化行为,确保符合预期。