每个Bean都有自己的作用域,它们会在特定的时间生成,在特定的范围生存。Spring IOC容器的bean有四种作用域:
其中默认的作用域是singleton,单例模式。也就是我们之前配置的bean的作用域模式,即所有的bean只有一个,并且在一开始就生成了。
prototype则是在每次getBean的时候都会生成一个新的实例。
request则是以每次请求作用作用域,session则是Http Session被创建的时候被创建的,并且作用域适用于WebApplicationContext环境。
好,我们今天主要看看前两者:
我们先将CarBean定义给出,这里我们在构造方法里加入了控制台输出信息。
package com.happyBKs.autowire;
public class CarBean {
String brand;
double price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public CarBean(String brand, double price) {
super();
this.brand = brand;
this.price = price;
}
public CarBean() {
super();
System.out.println(this.brand+" Constructor ....");
}
@Override
public String toString() {
return "CarBean [brand=" + brand + ", price=" + price + "]";
}
}
IOC容器配置:\src\main\resources\bean-scopes.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="carBM" class="com.happyBKs.autowire.CarBean" p:brand="BM"
p:price="400000" scope="singleton" />
<bean id="carAudi" class="com.happyBKs.autowire.CarBean" p:brand="Audi"
p:price="300000" scope="prototype" />
</beans>
测试代码:
@Test
public void testScope1() {
{
System.out.println("example 1:");
ApplicationContext ac = new ClassPathXmlApplicationContext("bean-scopes.xml");
System.out.println("getBean(carBM)");
CarBean cb = (CarBean) ac.getBean("carBM");
System.out.println(cb);
}
{
System.out.println("example 2:");
ApplicationContext ac = new ClassPathXmlApplicationContext("bean-scopes.xml");
System.out.println("getBean(carAudi)");
CarBean cb = (CarBean) ac.getBean("carAudi");
System.out.println(cb);
}
}
输出结果:
example 1:
七月 18, 2015 10:32:13 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@191d7bd5: startup date [Sat Jul 18 22:32:13 CST 2015]; root of context hierarchy
七月 18, 2015 10:32:13 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [bean-scopes.xml]
null Constructor ....
getBean(carBM)
CarBean [brand=BM, price=400000.0]
example 2:
七月 18, 2015 10:32:14 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@3e9c00ea: startup date [Sat Jul 18 22:32:14 CST 2015]; root of context hierarchy
七月 18, 2015 10:32:14 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [bean-scopes.xml]
null Constructor ....
getBean(carAudi)
null Constructor ....
CarBean [brand=Audi, price=300000.0]
注意了,第二个例子中有两个null Constructor ....
第一个是carBM在加载IOC容器配置文件时自动加载的,因为那个bean是singleton的作用域,即使不使用它,也会被构造。
第二个是在getBean时加载的,只有需要时才会被构造。
那么你也许会问?真的是重新被构造了吗?我再给例子吧。
我们分别用同一个容器,getBean两次,看看singleton和protoType作用域下返回对象的区别:
singleton
@Test
public void testScope2() {
ApplicationContext ac1 = new ClassPathXmlApplicationContext(
"bean-scopes.xml");
CarBean cb1 = (CarBean) ac1.getBean("carBM");
System.out.println(cb1);
CarBean cb2 = (CarBean) ac1.getBean("carBM");
System.out.println(cb2);
if(cb1==cb2)
{
System.out.println("the same one!");
}
else
{
System.out.println("different!");
}
}
输出:
七月 18, 2015 10:45:24 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@75e81ab3: startup date [Sat Jul 18 22:45:24 CST 2015]; root of context hierarchy
七月 18, 2015 10:45:24 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [bean-scopes.xml]
null Constructor ....
CarBean [brand=BM, price=400000.0]
CarBean [brand=BM, price=400000.0]
the same one!
protoType
@Test
public void testScope3() {
ApplicationContext ac1 = new ClassPathXmlApplicationContext(
"bean-scopes.xml");
CarBean cb1 = (CarBean) ac1.getBean("carAudi");
System.out.println(cb1);
CarBean cb2 = (CarBean) ac1.getBean("carAudi");
System.out.println(cb2);
if(cb1==cb2)
{
System.out.println("the same one!");
}
else
{
System.out.println("different!");
}
}
输出结果:
七月 18, 2015 10:46:12 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@72f9ebcd: startup date [Sat Jul 18 22:46:12 CST 2015]; root of context hierarchy
七月 18, 2015 10:46:12 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [bean-scopes.xml]
null Constructor ....
null Constructor ....
CarBean [brand=Audi, price=300000.0]
null Constructor ....
CarBean [brand=Audi, price=300000.0]
different!
但是,请注意,如果是不同的ApplicationContext,也就是两个不同的容器,那么无论什么作用域类型,返回的对象一定不是同一个。