在用Spring开发时,我们常用的注解修饰的Bean是单实例的,比如@Component、@Service、@Bean。
这些单例默认在Spring启动时加载到容器中,以后再调用时也不会重新创建,而是之间从容器中拿。
@Lazy注解只对单例有用,它让Bean在Spring启动时不会加载到容器中,只有在代码里第一次调用时才创建一次,加载到容器中,以后再次调用时,也只会到容器中拿。
@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;
}
}
/**
* 默认@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)
@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启动时不创建,第一次调用时才创建,以后再调用也不创建,直接从容器中拿。
对上面代码修改,测试失效情况
在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失效,具体代码实验看下面博客