Spring注解(@Scope @Lazy @Condition
@Scope注解指定注入容器的bean是单实例还是多实例的,默认情况下是单实例
@Configuration
public class MainConfig2 {
@Scope("prototype")
@Bean("person")
public Person person(){
return new Person("zhangsan",22);
}
}
ConfigurableBeanFactory#SCOPE_PROTOTYPE
@see ConfigurableBeanFactory#SCOPE_SINGLETON
@see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST request
@see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION sesssion@return
@Scope:调整作用域
prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。
每次获取的时候才会调用方法创建对象;
singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。
以后每次获取就是直接从容器(map.get())中拿,
request:同一次请求创建一个实例
session:同一个session创建一个实例
对比Spring xml 配置
<bean id="person" class="com.atguigu.bean.Person" scope="prototype" >
<property name="age" value="${}"></property>
<property name="name" value="zhangsan"></property>
</bean>
@Scope("prototype") 指定多实例测试代码
@Test
public void test2(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
// String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
// for (String beanDefinitionName : beanDefinitionNames) {
// System.out.println(beanDefinitionName);
// }
System.out.println("ioc容器创建完成");
Object person = applicationContext.getBean("person");
System.out.println(person);
Object person1 = applicationContext.getBean("person");
System.out.println(person1);
System.out.println(person==person1);
}
测试结果如下(每次获取bean,都会创建一个新的对象)
ioc容器创建完成
Person constructor....
Person [name=zhangsan, age=22, nickName=null]
Person constructor....
Person [name=zhangsan, age=22, nickName=null]
false
Process finished with exit code 0
懒加载:@Lazy
单实例bean:默认在容器启动的时候创建对象;
懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化;
@Configuration
public class MainConfig2 {
@Scope("singleton")
@Lazy
//@Scope("prototype")
@Bean("person")
public Person person(){
return new Person("zhangsan",22);
}
}
@Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean,Spring 底层大量使用的一个注解 可以标在类上,方法上
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
向容器中注入 bean
@Configuration
public class MainConfig2 {
@Scope("singleton")
@Lazy
//@Scope("prototype")
@Bean("person")
public Person person(){
return new Person("zhangsan",22);
}
@Bean("linux")
public Person person01(){
return new Person("Tom",10);
}
@Bean("windows")
public Person person02(){
return new Person("Jack",30);
}
}
案例:如果当前系统的是Linux就注入 bean(linux),是windows就注入 bean(windows)
- LinuxCondition、WindowsCondition 两个类都实现Condition 接口
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// TODO是否linux系统
//1、能获取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//2、获取类加载器
ClassLoader classLoader = conditionContext.getClassLoader();
//3、获取当前环境信息
Environment environment = conditionContext.getEnvironment();
//4、获取到bean定义的注册类
BeanDefinitionRegistry registry = conditionContext.getRegistry();
String property = environment.getProperty("os.name");
//可以判断容器中的bean注册情况,也可以给容器中注册bean
boolean definition = registry.containsBeanDefinition("person");
if(property.contains("linux")){
return true;
}
return false;
}
}
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if(property.contains("Windows")){
return true;
}
return false;
}
}
- 配置类中添加@Condition 注解 (标在方法上)
@Configuration
public class MainConfig2 {
@Scope("singleton")
@Lazy
//@Scope("prototype")
@Bean("person")
public Person person(){
return new Person("zhangsan",22);
}
@Conditional(LinuxCondition.class)
@Bean("linux")
public Person person01(){
return new Person("linus",10);
}
@Conditional(WindowsCondition.class)
@Bean("windows")
public Person person02(){
return new Person("bill",30);
}
}
- 测试(当前环境是Windows)
@Test
public void test3(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
//获取系统当前环境
Environment environment = applicationContext.getEnvironment();
String property = environment.getProperty("os.name");
System.out.println(property);
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
Map<String, Person> beansOfType = applicationContext.getBeansOfType(Person.class);
System.out.println(beansOfType);
}
- 测试结果
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig2
person
windows
Person constructor....
{person=Person [name=zhangsan, age=22, nickName=null], windows=Person [name=bill, age=30, nickName=null]}
Process finished with exit code 0
可以看到 由于是Windows环境,bean(Linux) 并没有注入到容器中
- 如果@Conditional 注解标在类上,满足当前条件,这个类中配置的所有bean注册才能生效
//类中组件统一设置。满足当前条件,这个类中配置的所有bean注册才能生效;
@Conditional({WindowsCondition.class})
@Configuration
public class MainConfig2 {
@Scope("singleton")
@Lazy
//@Scope("prototype")
@Bean("person")
public Person person(){
return new Person("zhangsan",22);
}
........
}