前言:
通过上一个demo,又进一步体会到了如何实现 spring 组件的注入。下面对注入到 IOC 容器中的组件的作用域作进一步说明。另外,这里还涉及到注入到容器中的 bean 的生命周期的问题。在后续博客中还会针对 bean 的生命周期作相关介绍。
实验:
- 准备配置类,注入 Person 组件:
package com.uestc.auto.xiaoxie.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.uestc.auto.xiaoxie.bean.Person;
@Configuration // 配置类
public class SpringConfig1 {
@Bean
public Person person(){
// System.out.println("向容器中添加Person组件");
return new Person("kristina", 24);
}
}
- 编写测试方法:为简化代码,将 ApplicationContext 的创建和容器的关闭分别放在 junit 的 before() 和 after() 方法中,这样不必在每一个单元测试方法中写重复的代码。
private AnnotationConfigApplicationContext context;
@Before
public void beforeMethod(){
context = new AnnotationConfigApplicationContext(SpringConfig1.class);
}
@Test
public void testScope() {
Person person = (Person)context.getBean("person");
Person person2 = (Person)context.getBean("person");
System.out.println(person == person2); // true,即默认创建的 bean 是单例的
}
@After
public void afterMethod(){
context.close();
}
- 修改配置类:在注入 Person 对象的时候,通过 @Scope 注解的 scopeName 属性指定 bean 的作用域为多例。再次进行测试,发现两次获取的 person 并非同一个对象了。
@Bean
@Scope(scopeName=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Person person(){
System.out.println("向容器中添加Person组件");
return new Person("kristina", 24);
}
由下图可以看出,scopeName 四种不同的取值对应了四种不同的作用域:
scopeName的取值 | 对应的含义 |
---|---|
ConfigurableBeanFactory.SCOPE_PROTOTYPE | 多例 |
ConfigurableBeanFactory.SCOPE_SINGLETON | 默认值,单例 |
WebApplicationContext.SCOPE_REQUEST | 如果设置为此值的话,在web应用中一个请求会是一个对象。 |
WebApplicationContext.SCOPE_SESSION | 如果设置为此值的话,在web应用中一个session会话会是一个对象。 |
- 下面对单实例和多实例对象的创建时机进行测试:为更好地看到实验效果,在配置类的 public Person person() 方法体中多添加一句 sysout 语句:System.out.println(“向容器中添加Person组件”)。然后,将单元测试方法(testScope)的方法体注释掉,即只创建 ApplicationContext 对象。
在单例模式下,重新运行,发现在创建 context 对象的时候就会调用 person() 方法,注入 Person 组件;
改为多例模式,重新运行,发现创建 context 对象的时候并不会去调用 person() 方法,而是在真正 context.getBean() 的时候才会注入 Person 组件。
即在单例模式下,在IOC容器初始化的时候就会创建对象。后面用的时候,拿到的也都是同一个对象;
而在多例模式下,IOC容器初始化的时候并不会创建对象,在 getBean() 的时候才会创建相应的对象。
- @Lazy 注解:
上面也提到了,在单例模式下,IOC容器初始化的时候就会创建相应的bean;懒加载(@Lazy)可以实现的效果:用的时候(getBean())才去创建相应的bean,而不是容器初始化的时候就创建。
@Lazy
// @Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean
public Person person(){
System.out.println("向容器中添加Person组件");
return new Person("Arianna", 28);
}