Spring注解学*之:@Scope,@Lazy,@Conditional

发布于:2021-07-30 09:39:00

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的作用域进行修改,相当于配置文件中标签的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 beansOfType = alicationContext.getBeansOfType(Student.class);
for (Map.Entry stringStudentEntry : beansOfType.entrySet()) {
System.out.println(stringStudentEntry.getKey());
System.out.println(stringStudentEntry.getValue());
}
}
}

结果:



当前运行环境是windows,然后创建了windows,搞定。


相关推荐

最新更新

猜你喜欢