(1)5大作用域
①singleton:在IOC容器中仅存在一个Bean实例,每次返回的都是同一个实例,Bean以单实例的方式存在
②prototype:每次调用getBean()时都会返回一个新的实例
③request:每次HTTP请求都会创建一个新的bean,该作用域仅适用于WebApplicationContext环境
④session:同一个HTTP Session共享一个Bean,不同的HTTP Session 使用不同的Bean。该作用域仅适用于WebApplicationContext环境
⑤global session:和session类似,不过仅在使用portlet context的时候有效。
singleton和prototype是比较原始、比较常用的作用域,目前我们只需要了解这2种作用域。
request、session以及global session这3个作用域,仅仅在基于web的IOC容器(如XmlWebApplicationContext)中有用。如果尝试在普通的 IOC容器(如:XmlBeanFactory或ClassPathXmlApplicationContext)中,使用这些作用域,你将会得到一个IllegalStateException异常(未知的bean作用域)。
这里我们只介绍singleton和prototype,后续再介绍另外3种
(2)通过bean标签的scope属性设置作用域
<bean id="... " class="... " scope="prototype"></bean>
(3)缺省(默认)作用域是singleton
<!-- 没有配置scope属性,默认是singleton -->
<bean id="... " class="... "></bean>
(4)单例bean(作用域为singleton 的bean)
①在创建IOC容器对象时:调用bean的构造器来实例化bean对象;调用set方法为bean的属性赋值。代码验证:
public class HelloWorld {
private String name;
public void setName(String name) {
System.out.println("为属性name赋值");
this.name = name;
}
public HelloWorld(){
System.out.println("无参构造器");
}
}
public class Main {
public static void main(String[] args) {
//创建IOC容器对象
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
}
}
执行结果:
②每次调用getBean(),返回的都是同一个实例。代码示例:
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("===========================");
HelloWorld h1=(HelloWorld)context.getBean("hello");
System.out.println(h1);
HelloWorld h2=(HelloWorld)context.getBean("hello");
System.out.println(h2);
System.out.println(h1==h2);
}
运行结果:
③对于单例bean,只调用一次构造方法(初始化容器对象时),只有一个实例对象,每次调用getBean()返回的都是该实例
(5)原型bean(作用域为prototype的bean)
①在每次调用getBean()时:调用bean的构造器来实例化新的bean对象;调用set方法为bean的属性赋值。
<!-- 把作用域设置为 prototype-->
<bean id="hello" class="com.HelloWorld" scope="prototype">
<property name="name" value="Spring"></property>
</bean>
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("===========================");
HelloWorld h1=(HelloWorld)context.getBean("hello");
System.out.println(h1);
HelloWorld h2=(HelloWorld)context.getBean("hello");
System.out.println(h2);
System.out.println(h1==h2);
}
运行结果:
2)每次调用getBean(),返回的是新的实例
总结:
(1)单例bean(作用域为singleton)
实例化容器对象时,创建bean对象(由IOC容器来创建);
在容器中只维持一个,每次调用getBean()取出的都是同一个;
IOC容器关闭时,销毁单例bean。即销毁取决于Spring容器;
单例bean完全是由IOC容器管理。
(2)原型bean(作用域为prototype)
每次调用getBean()时,创建一个新的bean对象并返回,由IOC容器来创建;
每次取出的都是新的bean对象,并非同一个;
原型bean不是由Spring容器销毁,而是被JVM自动回收(当处于未引用状态时);
IOC创建原型bean后,就不再管他了,因此原型bean并非完全交给Spring容器进行管理的。
对象的创建和销毁,会增加系统的开销。因此,除非必要,否则尽量避免将Bean被设置成prototype作用域。