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項目,導入如下兩個依賴:
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
創建一個實體類:
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代理模式。
有什麼不足的地方,希望大家指正出來,關於代理模式,我也會繼續補充。