开发技巧!@Lazy注解这5种用法非常实用

文摘   2025-01-16 08:02   新疆  

Spring Boot 3实战案例合集》现已囊括超过80篇精选实战文章,并且此合集承诺将永久持续更新,为您带来最前沿的技术资讯与实践经验。欢迎积极订阅,享受不断升级的知识盛宴!订阅用户将特别获赠合集内所有文章的最终版MD文档(详尽学习笔记),以及完整的项目源码,助您在学习道路上畅通无阻。

【重磅发布】《Spring Boot 3实战案例锦集》PDF电子书现已出炉!

🎉🎉我们精心打造的《Spring Boot 3实战案例锦集》PDF电子书现已正式完成,目前已经有80个案例,后续还将继续更新。文末有电子书目录。

💪💪永久更新承诺

我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务。这意味着,随着技术的不断发展和Spring Boot 3的深入应用,我们的电子书也将持续更新,确保您始终掌握最前沿、最实用的技术知识。

🔥🔥精彩内容不容错过
《Spring Boot 3实战案例锦集》汇聚了众多精心挑选的实战案例,旨在帮助您快速掌握Spring Boot 3的核心技术和实战技巧。无论您是初学者还是有一定经验的开发者,都能从中受益匪浅。

💌💌如何获取
请立即订阅我们的合集点我订阅,并通过私信联系我们,我们将第一时间将电子书发送给您。

现在就订阅合集


环境:Spring6.1.8



1. 简介

Spring中的@Lazy注解主要用于实现惰性加载(延迟加载),它可以应用在类、方法、构造方法、参数和字段上。以下是@Lazy注解的作用、应用场景

1.1 作用

在Spring框架中,默认情况下,所有的Bean在容器启动时都会被初始化。但是,有些Bean的初始化可能涉及到一些重量级的操作,如网络IO操作、复杂计算等,这些操作会消耗大量的系统资源。通过使用@Lazy注解,可以让这些Bean在真正需要时才进行初始化,从而提高系统的启动速度和性能。

1.2 应用场景

  • 提升系统启动速度:当应用包含大量的Bean,如果存在某些Bean初始化操作非常耗时(如网络IO操作或复杂耗时计算),通过@Lazy注解可以显著提升系统的启动速度。如:应用启动时,需要从Redis读取大量的缓存数据,如果将此Bean使用@Lazy标注,那么应用启动会非常快,而当在使用缓存服务时才去读取redis初始化数据。

  • 解决循环依赖:如果两个Bean之间存在循环依赖,即A依赖B,B又依赖A(构造函数注入),这会导致Spring容器在初始化这些Bean时陷入死循环。使用@Lazy注解可以解决这类问题。

  • 单例Bean正确注入多例Bean:如果A是单例,B是多例,在A中注入B实例,要想正确的注入(每次使用B时都是新对象)通过使用@Lazy能够轻松解决。

以上是关于@Lazy注解的简介及应用场景,接下来将详细介绍@Lazy的5种使用方式。

2. 实战案例

2.1 环境准备

public class PersonDAO {}public class PersonService {   private PersonDAO dao ;      public String toString() {     return "PersonService [dao=" + dao.getClass() + "]";   }}// 测试入口代码try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {  context.register(PersonDAO.class) ;  context.register(PersonService.class) ;  context.refresh() ;
System.out.println(context.getBean(PersonService.class)) ;}

接下的每个示例都将基于上面的类进行。

2.2 字段注入

// @Resource// @Autowired@Lazyprivate PersonDAO dao ;

输出结果

PersonService [dao=class com.pack.PersonDAO$$SpringCGLIB$$0]

通过@Lazy标注的字段,最终注入的是代理类(不管上面使用的@Resource还是@Autowired)。

注:在上面测试入口代码中,我们使用的是AnnotationConfigApplicationContext,如果你使用的是GenericApplicationContext那么在默认情况下@Autowired是不会生效的,这时候你还需要做如下设置:
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory() ;beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()) ;

将此BeanFactory设置到ApplicationContext中即可。

2.3 方法注入

@Resource@Lazypublic void setPersonDAO(PersonDAO dao) {  this.dao = dao ;}

输出结果

PersonService [dao=class com.pack.PersonDAO$$SpringCGLIB$$0]

同样的生成了代理。

方法注入,你还可以将@Lazy放到方法参数上,如下示例:

@Resourcepublic void setPersonDAO(@Lazy PersonDAO dao) {  this.dao = dao ;}

这种方式也是会被生成代理对象。

2.4 构造函数注入

@Lazypublic PersonService(PersonDAO dao) {  this.dao = dao ;}

输出结果

PersonService [dao=class com.pack.PersonDAO$$SpringCGLIB$$0]

同样,注解也可以使用在参数上

public PersonService(@Lazy PersonDAO dao) {  this.dao = dao ;}

构造函数注入与方法注入基本一致。

2.5 单例Bean注入多例Bean

修改PersonDAO

@Scope("prototype")public class PersonDAO {}

通过@Scope将其声明为多例。

修改PersonService随意添加一个方法。

public class PersonService {  @Autowired  private PersonDAO dao ;  public void save() {    System.out.printf("PersonDAO hashCode: %s%n", dao) ;  }}

测试类

PersonService ps = context.getBean(PersonService.class);ps.save() ;ps.save() ;ps.save() ;

当dao字段上不添加@Lazy注解时,输出结果:

PersonDAO hashCode: com.pack.PersonDAO@66565121PersonDAO hashCode: com.pack.PersonDAO@66565121PersonDAO hashCode: com.pack.PersonDAO@66565121

每次都是同一个对象,这不是我们期望的结果

dao字段添加@Lazy注解后,再次运行

PersonDAO hashCode: com.pack.PersonDAO@73a2e526PersonDAO hashCode: com.pack.PersonDAO@13f95696PersonDAO hashCode: com.pack.PersonDAO@68be8808

正确的输出结果,每次使用都是不同的实例。

2.6 循环依赖

class class A {  private B b ;  public A(B b) {    this.b = b ;  }}public class B {  private A a ;  public B(A a) {    this.a = a ;  }}

上面的依赖通过构造方法注入,这种情况下容器启动是会报错的,如下:

出现循环依赖错误,通过@Lazy注解解决此问题,只需要在任意类的构造函数上使用@Lazy注解,如下:

public A(@Lazy B b) {  this.b = b ;}

只需要在其中一方加入了@Lazy注解后,问题得到解决。

以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏

推荐文章

优雅!Spring 基于 Plugin 插件开发(官方推荐)

Spring Boot 多版本API控制 5 种实现方案

高级开发!自定义注解100行代码实现 @Resource/@Autowired 注入功能

技术专家!Spring Boot 增强版 @RequestMapping 添加限流功能

优雅!基于Spring Boot字段加密后的模糊查询,支持MyBatis, JPA

从SpringBoot2.7开始自动配置发生哪些变化?你都知道吗?

Spring非常强大的2个类知道的人不多

Spring Boot启动时必须对配置信息做有效性校验

SpringBoot项目中这10个开发技巧你都知道吗?

必须掌握SpringBoot强大的日志功能

SpringBoot3使用虚拟线程一定要小心了

要不要升级?Java 21强大的新特性,代码量减半

两种方式实现SpringBoot外部配置实时刷新最佳实践

Spring6.2新特性@Fallback候选Bean

实战案例SpringBoot整合Seata AT模式实现分布式事务【超详细】

Spring全家桶实战案例源码
spring, springboot, springcloud 案例开发详解
 最新文章