Scope:也叫做作用域,在Spring IoC中的作用是指它创建的Bean对象对于其他Bean对象的请求的可视范围,Spring IoC容器中定义5种常用作用域:
在Spring2.0:
1).singleton:单实例的(Spring Ioc默认的方式),在IOC容器启动时就会调用方法创建对象放入IOC容器中,在容器中只存在一份。
2).prototype:多实例的,在IOC容器启动时不会主动调用方法创建对象放入IOC容器中,而是每次获取的时候才会调用方法创建对象。
在Spring2.0之后新增了三种为支持web应用的ApplicationContext,增强另外三种
1).request:同一次请求只创建一个对象,也就是会为每个Http请求创建一个对象,请求结束后该对象生命周期结束。
2).session:对于每次HTTP Session,使用session定义的Bean都将产生一个新实例。
3).global session:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。
注意的是:上面三种只有在Web应用中使用Spring时,该作用域才会生效。
在实际应用中,我们常用的主要是singleton和prototype这两种:
创建一个maven项目,导入如下两个依赖:
org.springframework
spring-context
4.1.2.RELEASE
junit
junit
4.12
创建一个实体类:
package bean;
/**
* @program: springannot
* @description: bean
* @author: han
* @create: 2019-11-09 15:27
* @xgr:
* @description:
**/
public class Person {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
public Person(String name, String age) {
this.name = name;
this.age = age;
}
public Person() {
}
}
1、Singleton:单实例
创建一个配置类:用@Configuration注明为配置类,并注册到容器当中。用@Scope定义它的域,默认就是单实例的,也可以声明使用value属性。
@Configuration
public class MainConfig {
@Bean(name = "person")
@Scope
public Person per() {
System.out.println("创建person添加容器中");
return new Person("张三", "18");
}
}
1.1 :测试单实例是否为自动注入
package test;
import config.MainConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestScope {
@Test
public void test01(){
//创建IOC
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
System.out.println("容器创建完成");
String[] names = applicationContext.getBeanDefinitionNames();
for(String str : names){
System.out.println("str:"+str);
//可以看到除了Spring自己的Bean对象,也可以看到我们声明的Person对象。
}
}
}
在这里我们也证明了单实例的会在容器启动时默认的注册到容器中,但是这也不是绝对的我们能使用@Lazy懒加载(容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化。),相当于过去的xml文件中bean属性的lazy属性,@Lazy注解有个值为布尔类型的value属性,默认为true也就是使用懒加载。
@Configuration
public class MainConfig {
@Bean(name = "person")
@Scope
@Lazy
public Person per() {
System.out.println("创建person添加容器中");
return new Person("张三", "18");
}
}
此时我们在使用test01,测试时会发现没用Person这个对象了,只有我们手动是得到这个Bean才会创建,对于单例的无论你get多少个对象,它也只存在一份,例如:
package test;
import config.MainConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestScope {
@Test
public void test01(){
//创建IOC
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
System.out.println("容器创建完成");
String[] names = applicationContext.getBeanDefinitionNames();
for(String str : names){
System.out.println("str:"+str);
//可以看到除了Spring自己的Bean对象,也可以看到我们声明的Person对象。
Object o = applicationContext.getBean("person");
Object o1 = applicationContext.getBean("person");
System.out.println("o:"+o);
System.out.println("o1:"+o1);
System.out.println("o==o1:"+(o == o1));
}
}
}
打印日志:
创建person添加容器中
o:Person{name='张三', age='25'}
o1:Person{name='张三', age='25'}
o==o1:true
2、prototype:多实例的,在IOC容器启动时不会调用方法创建对象放在容器中,而是在每次获取的时候才会调用方法创建对象
我们还是使用之前的person,将@Scope的属性设置为prototype。
@Configuration
public class MainConfig {
@Bean(name = "person")
@Scope(value = "prototype")
public Person per() {
System.out.println("创建person添加容器中");
return new Person("张三", "18");
}
}
测试
package test;
import config.MainConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestScope {
@Test
public void test01(){
//创建IOC
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
System.out.println("容器创建完成");
Object o = applicationContext.getBean("person");
Object o1 = applicationContext.getBean("person");
System.out.println("o:"+o);
System.out.println("o1:"+o1);
System.out.println("o==o1:"+(o == o1));
}
}
打印日志:
容器创建完成
创建person添加容器中
创建person添加容器中
o:Person{name='张三', age='18'}
o1:Person{name='张三', age='18'}
o==o1:false
我们能看到o==o1为false,说明在容器中每次声明得到Person时都会创建一个对象,在容器中会存在多份。
关于@Scope,点开源码我们看到文中讲到的@Scope,还有一个@proxyMode代理模式。
有什么不足的地方,希望大家指正出来,关于代理模式,我也会继续补充。