SpringBoot教程(5) 单例Bean懒加载 @Lazy的使用和失效情况

孔安福
2023-12-01

一、@Lazy的作用

在用Spring开发时,我们常用的注解修饰的Bean是单实例的,比如@Component、@Service、@Bean。
这些单例默认在Spring启动时加载到容器中,以后再调用时也不会重新创建,而是之间从容器中拿。

@Lazy注解只对单例有用,它让Bean在Spring启动时不会加载到容器中,只有在代码里第一次调用时才创建一次,加载到容器中,以后再次调用时,也只会到容器中拿。

二、测试@Lazy在启动时不会创建Bean

1. 先创建简单的类User、Person

@Data
public class User {

    private String name;

    private int age;

    public User(){
        System.out.println("初始化:User()");
    }

    public User(String name, int age) {
        System.out.println("初始化:User(String name, int age)");
        this.name = name;
        this.age = age;
    }
}
@Data
public class Person {

    private String name;

    private int age;

    public Person(){
        System.out.println("初始化:Person()");
    }

    public Person(String name, int age) {
        System.out.println("初始化:Person(String name, int age)");
        this.name = name;
        this.age = age;
    }
}

2. 利用@Configuration+@Bean创建单例

/**
 * 默认@Configuration下@Bean定义的是单实例
 * 也就是Spring启动时,就已经加载到Spring容器中了
 * @Lazy是延迟加载,只有第一次调用Bean时才加载到容器中
 */
@Configuration
public class MyConfig {

    @Lazy
    @Bean(name = "myBeanPerson")
    public Person myBeanPerson(){
        return new Person("king", 31);
    }

    @Bean(name = "myBeanUser")
    public User myBeanUser(){
        return new User("king", 31);
    }
}

运行项目,只有User的构造器的输出,说明只创建了User的实例

初始化:User(String name, int age)

3. 测试@Lazy修饰的对象的第一次创建

@SpringBootApplication
@ComponentScan(value = "info.pigg.study.java")
public class DictApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(DictApplication.class, args);

        System.out.println("===Spring启动完毕,测试代码开始===");
        Object person01 = run.getBean("myBeanPerson");

        Object person02 = run.getBean("myBeanPerson");

        System.out.println("person01 == person02 : " + (person01 == person02));

        Object user01 = run.getBean("myBeanUser");

        Object user02 = run.getBean("myBeanUser");

        System.out.println("user01 == user02 : " + (user01 == user02));
}

输出如下:

初始化:User(String name, int age)

===Spring启动完毕,测试代码开始===
初始化:Person(String name, int age)
person01 == person02 : true
user01 == user02 : true

Person的Bean是懒加载的,Spring启动时不创建,第一次调用时才创建,以后再调用也不创建,直接从容器中拿。

三、@Lazy的失效

对上面代码修改,测试失效情况

在User里用了@Autowired Person myPerson;

@Data
public class User {
    
    @Autowired
    Person myPerson;

    private String name;

    private int age;

    public User(){
        System.out.println("初始化:User()");
    }

    public User(String name, int age) {
        System.out.println("初始化:User(String name, int age)");
        this.name = name;
        this.age = age;
    }
}

运行结果如下:

初始化:User(String name, int age)
初始化:Person(String name, int age)
===Spring启动完毕,测试代码开始===
person01 == person02 : true
user01 == user02 : true

可以看到@Lazy好像失效了,没有起作用。

如果只在某个类上添加@Lazy注解,如果工程中有其它地方依赖了该类,那么即使添加了@Lazy注解,也依然会在IoC容器初始化的时候就去实例化该类。

如果想在使用的时候才去实例化,可以在每个依赖该类的地方上添加@Lazy注解。例如下面代码,Person还是懒加载的。

@Data
public class User {

    //添加了@Lazy
    @Lazy
    @Autowired
    Person myPerson;

    private String name;

    private int age;

    public User(){
        System.out.println("初始化:User()");
    }

    public User(String name, int age) {
        System.out.println("初始化:User(String name, int age)");
        this.name = name;
        this.age = age;
    }
}

还有@DependsOn注解也会让@Lazy失效,具体代码实验看下面博客

SpringBoot教程(9) @DependsOn 设置Bean依赖 结合@Lazy 修改Bean加载顺序

 类似资料: