@Scope-设置组件作用域
如果不使用@Scope设置组件的作用域, 那么默认组件作用域都是singleton(单实例的)
首先我们来看一下@Scope都有哪几种作用域:
查看@Scope源码, 主要关注value属性值的取值:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
/**
* Alias for {@link #scopeName}.
* @see #scopeName
*/
@AliasFor("scopeName")
String value() default "";
/**
* Specifies the name of the scope to use for the annotated component/bean.
* <p>Defaults to an empty string ({@code ""}) which implies
* {@link ConfigurableBeanFactory#SCOPE_SINGLETON SCOPE_SINGLETON}.
* @since 4.2
* @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
* @see ConfigurableBeanFactory#SCOPE_SINGLETON
* @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
* @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
* @see #value
*/
@AliasFor("value")
String scopeName() default "";
...
}
可以看到取值主要分为四种:
* @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
* @see ConfigurableBeanFactory#SCOPE_SINGLETON
* @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
* @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
- prototype : 多实例的
- singleton : 单实例的
- request : 同一个请求创建一个实例
- session : 同一个Session创建一个实例
可以发现request和session都是在web工程中使用的
如果作用域是单实例, 那么默认是IOC容器启动的时候就会创建单例对象放到IOC容器中的单例map中
package com.ffyc.spring.config;
import com.ffyc.spring.model.Person;
import org.springframework.context.annotation.*;
@Configuration
@ComponentScan(value = "com.ffyc.spring")
public class PersonConfig {
@Bean
public Person getPerson() {
System.out.println("创建person实例...");
return new Person();
}
}
测试:
package com.ffyc.spring.test;
import com.ffyc.spring.config.PersonConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test3 {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(PersonConfig.class);
}
}
可以看到, 我们只是启动IOC容器的时候就调用了PersonConfig中的getPerson()方法
如果作用域是多实例, 那么默认不是在IOC容器启动的时候创建实例, 而是在每次使用IOC容器调用getBean()方法获取该实例的时候就调用该方法创建一个对象并返回
- 值得注意的是 : 多实例对象是不会存储在IOC容器中的, 如果是多实例对象, 那么就是每次需要使用的时候就创建一个并返回, 并不会将该多实例对象放到IOC容器中
package com.ffyc.spring.config;
import com.ffyc.spring.model.Person;
import org.springframework.context.annotation.*;
@Configuration
@ComponentScan(value = "com.ffyc.spring")
public class PersonConfig {
@Bean
@Scope("prototype")
public Person person() {
System.out.println("创建person实例...");
return new Person();
}
}
测试:
package com.ffyc.spring.test;
import com.ffyc.spring.config.PersonConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test3 {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(PersonConfig.class);
}
}
发现启动IOC容器的时候确实没用创建该实例对象
测试:
package com.ffyc.spring.test;
import com.ffyc.spring.config.PersonConfig;
import com.ffyc.spring.model.Person;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test3 {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(PersonConfig.class);
System.out.println(annotationConfigApplicationContext.getBean("person"));
}
}
发现确实是使用IOC容器调用getBean()方法的时候创建的多实例对象
扩展 : 懒加载(延时加载)
如果是作用域是单例, 添加@Lazy注解之后也就是只有使用IOC容器调用getBean()方法获取该单例实例的时候才调用对应的方法创建该实例, 而不是容器启动的时候就创建该实例
package com.ffyc.spring.config;
import com.ffyc.spring.controller.MyTypeFilter;
import com.ffyc.spring.model.Person;
import org.springframework.context.annotation.*;
@Configuration
@ComponentScan(value = "com.ffyc.spring")
public class PersonConfig {
@Bean
@Lazy
@Scope("singleton")
public Person person() {
System.out.println("创建person实例...");
return new Person();
}
}
测试:
package com.ffyc.spring.test;
import com.ffyc.spring.config.PersonConfig;
import com.ffyc.spring.model.Person;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test3 {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(PersonConfig.class);
}
}
发现确实不是IOC容器启动的时候完成的创建实例
测试:
package com.ffyc.spring.test;
import com.ffyc.spring.config.PersonConfig;
import com.ffyc.spring.model.Person;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test3 {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(PersonConfig.class);
System.out.println(annotationConfigApplicationContext.getBean("person"));
}
}
发现确实是IOC第一次调用getBean()方法获取该实例的时候完成的创建