1、@Scope
首先,有一点需要说明,在SpringIOC容器中,所有注册的bean(controller,service,dao,....),默认情况下都是单实例的,及singleton;那有哪些作用域,分别什么意思?如下表:
作用域 | 解释说明 |
singleton | 单实例,在创建IOC时,bean就会被创建,而且只会创建一次,以后都会直接使用该创建对象,相当于map.get();注意:在IOC容器创建的时候,就已经创建好了bean; |
prototype | 多实例,在创建IOC时,bean不会被创建,只有当bean的创建方法被调用时,才会创建,而且每次调用,每次创建; |
request | 同一个请求时,创建一次; |
session | 同一个session,创建一次; |
spring提供可以通过@Scope来对bean的作用域进行修改,相当于配置文件中<bean>标签的scope属性,@Scope的取值有singleton,prototype,request以及session,含义如上表;如果不指定,默认为singleton;
做个测试看一下:
测试一,不写@Scope,或者写了@Scope,不指定内容
1、Myconfig
@Configuration
public class MyConfig {
@Bean
@Scope
public Student student(){
System.out.println("创建student开始");
return new Student(14,"idea");
}
}
-------------------------------------------
2、测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootAnnocationApplicationTests {
@Test
public void contextLoads() {
System.out.println("开始创建IOC容器...");
ApplicationContext alicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
System.out.println("IOC容器创建完毕...");
Object student1 = alicationContext.getBean("student");
Object student2 = alicationContext.getBean("student");
//如果前后创建的不是同一个对象,那么==一定为false
System.out.println(student1 == student2);
}
}
结果:
先不管我说的那个问题,我需要看一下。在打印“开始创建IOC容器...”和“IOC容器创建完毕...”时,student就已经创建了,而且我调用了2次,值打印了一次,而且==为true;验证了单例的结论;
测试二:@Scope指定为prototype
直接看结果:
“创建student开始”在“IOC容器创建完毕...”才打印,而且==为false,验证了prototype是在IOC创建之后,调用时才创建的结论,而且每次调用,每次创建!
2、@Lazy:延迟加载;该注解主要是和@Scope("singleton")结合使用,目的是为了让bean在IOC容器创建之后再创建,当然也只是创建一个;
测试:
1、MyConfig 配置类
@Configuration
public class MyConfig {
@Bean
@Lazy
public Student student(){
System.out.println("创建student开始");
return new Student(14,"idea");
}
}
--------------------------------------------
2、测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootAnnocationApplicationTests {
@Test
public void contextLoads() {
System.out.println("开始创建IOC容器...");
ApplicationContext alicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
System.out.println("IOC容器创建完毕...");
Object student1 = alicationContext.getBean("student");
Object student2 = alicationContext.getBean("student");
System.out.println(student1 == student2);
}
}
结果:
可以看到,“创建student开始”在“IOC容器创建完毕...”打印完之后才打印,说明延迟加载了,而且只打印了一遍,且==为true,符合单例特性;
3、@Conditional,这个就NB了,springboot底层大量使用了该注解,意思就是根据不同的条件,进行特定创建;首先看个需求,根据当前JVM的操作系统不同,创建不同的bean;
首先@Conditional的值,是实现了condition接口的一个实现类的数组集合,根据上面的条件,我们需要建两个类,一个WindowsCondition和LinuxCondition,分别实现condition接口;condition接口中有一个match方法,用于实现具体业务,详情见下文:
1、MyConfig 类
@Configuration
public class MyConfig {
@Bean
@Conditional(WindowsCondition.class)
public Student windows(){
return new Student(14,"windows");
}
@Bean
@Conditional(LinuxCondition.class)
public Student linux(){
return new Student(14,"linux");
}
}
---------------------------------------------------------
2、WindowsCondition 类
public class WindowsCondition implements Condition {
/**
* conditionContext : 能使用的上下文,也就是环境
* annotatedTypeMetadata:标注了condition的注释信息
*/
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
/**
* 如果环境是windows,返回true
*/
//能获取到IOC使用的bean工厂
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//能获取到类加载器
ClassLoader classLoader = conditionContext.getClassLoader();
//能获取到注册信息
BeanDefinitionRegistry registry = conditionContext.getRegistry();
//能获取到运行环境
Environment environment = conditionContext.getEnvironment();
String property = environment.getProperty("os.name");
if(property.contains("Windows")){
return true;
}
return false;
}
}
---------------------------------------------------
3、LinuxCondition 类
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();
String property = environment.getProperty("os.name");
if(property.contains("Linux")){
return true;
}
return false;
}
}
-------------------------------------------------
4、测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootAnnocationApplicationTests {
@Test
public void contextLoads() {
ApplicationContext alicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
Environment environment = alicationContext.getEnvironment();
System.out.println(environment.getProperty("os.name"));
Map<String, Student> beansOfType = alicationContext.getBeansOfType(Student.class);
for (Map.Entry<String, Student> stringStudentEntry : beansOfType.entrySet()) {
System.out.println(stringStudentEntry.getKey());
System.out.println(stringStudentEntry.getValue());
}
}
}
结果:
当前运行环境是windows,然后创建了windows,搞定。