开发者不仅可以控制注入不同的依赖到Bean之中,也可以配置Bean的作用域。这种方法是非常强大而且弹性也非常好的。开发者可以通过配置来指定对象的作用域,而不用在Java类层次上来配置。Bean可以配置多种作用域。 Spring框架支持5种作用域,有三种作用域是当开发者使用基于web的ApplicationContext的时候才生效的。
一、Bean的作用域
作用域 | 描述 |
---|---|
单例(singleton) | (默认)每一个Spring IoC容器都拥有唯一的一个实例对象 |
原型(prototype) | 一个Bean定义可以创建任意多个实例对象 |
请求(request) | 一个HTTP请求会产生一个Bean对象,也就是说,每一个HTTP请求都有自己的Bean实例。只在基于web的Spring ApplicationContext中可用 |
会话(session) | 限定一个Bean的作用域为HTTPsession的生命周期。同样,只有基于web的Spring ApplicationContext才能使用 |
全局会话(global session) | 限定一个Bean的作用域为全局HTTPSession的生命周期。通常用于门户网站场景,同样,只有基于web的Spring ApplicationContext可用 |
应用(application) | 限定一个Bean的作用域为ServletContext的生命周期。同样,只有基于web的Spring ApplicationContext可用 |
Spring的单例Bean和与设计模式之中的所定义的单例模式是有所区别的。设计模式中的单例模式是将一个对象的作用域硬编码的,一个ClassLoader只有唯一的一个实例。 而Spring的单例作用域,是基于每个容器,每个Bean只有一个实例。这意味着,如果开发者根据一个类定义了一个Bean在单个的Spring容器中,那么Spring容器会根据Bean定义创建一个唯一的Bean实例。 单例作用域是Spring的默认作用域,下面的例子是在基于XML的配置中配置单例模式的Bean。
新建beanScope-applicationContext.xml
<bean id = "myCoach"
class = "springdemo.TrackCoach">
<!-- set up constructer injection -->
<constructor-arg ref = "myFortune" />
</bean>
新建BeanScopeDemo .java
public class BeanScopeDemo {
public static void main(String[] args) {
// load the spring configuration file
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("beanScope-applicationContext.xml");
//retrieve bean from spring container
Coach theCoach = context.getBean("myCoach",Coach.class);
Coach alphaCoach = context.getBean("myCoach",Coach.class);
//check if they are the same
boolean result = (theCoach == alphaCoach);
//print out the results
System.out.println("\nPointing to the same object:" + result);
System.out.println("\nMemory location for theCoach"+theCoach);
System.out.println("\nMemory location for alphaCoach"+alphaCoach + "\n");
//close the context
context.close();
}
}
Pointing to the same object:true
Memory location for theCoachspringdemo.TrackCoach@10bbd20a
Memory location for alphaCoachspringdemo.TrackCoach@10bbd20a
2.prototype的bean scope就可以创建多个实例对象
修改xml文件
<bean id = "myCoach"
class = "springdemo.TrackCoach"
scope = "prototype">
输出结果:
Pointing to the same object:false
Memory location for theCoachspringdemo.TrackCoach@10bbd20a
Memory location for alphaCoachspringdemo.TrackCoach@48503868
二、 Bean生命周期
Spring Bean的完整生命周期从创建Spring容器开始,直到最终Spring容器销毁Bean.。
在spring的实际开发过程中,我们可能常常需要使用到init method和destroy method,比如初始化一个对象(bean)后立即初始化(加载)一些数据,在销毁一个对象之前进行垃圾回收等等。
新建BeanLifeCycleDemo.java
public class BeanLifeCycleDemo {
public static void main(String[] args) {
// load the spring configuration file
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("beanLifeCycle-applicationContext.xml");
//retrieve bean from spring container
Coach theCoach = context.getBean("myCoach",Coach.class);
System.out.println(theCoach.getDailyWorkout());
//close the context
context.close();
}
}
在TrackCoach.java中定义初始化TrackCoach
public class TrackCoach implements Coach {
public void doMystartupStuff() {
System.out.println("TrackCoach: inside method doMyStartupStuff");
}
//add a destroy method
public void doMyCleanupStuffYoYo() {
System.out.println("TrackCoach: inside method doMyCleanupStuffYoYo");
}
}
TrackCoach: inside method doMyStartupStuff
Run a hard 5k
TrackCoach: inside method doMyCleanupStuffYoYo
<bean id = "myCoach"
class = "springdemo.TrackCoach"
init-method = "doMystartupStuff"
destroy-method = "doMyCleanupStuffYoYo">
使用annatotion(java注释)设置生命周期
@PostConstruct
public void doMyStartupStuff() {
System.out.println(">> TennisCoach: doMyStartupStuff");
}
//define destory method
@PreDestroy
public void doMyCleanupStuff() {
System.out.println(">> TennisCoach: doMyCleanupStuff");
}
运行main函数输出结果:
>> TennisCoach: doMyStartupStuff
The journey is the reward
>> TennisCoach: doMyCleanupStuff
使用annatotion)设置bean scope
首先看他默认使用的是singleton作用域,在创建对象的时候link到同一个内存空间:
public class AnnotatioonBeanScopeDemoApp {
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
Coach theCoach = context.getBean("tennisCoach",Coach.class);
Coach alphaCoach = context.getBean("tennisCoach",Coach.class);
System.out.println(theCoach == alphaCoach);
System.out.println("Memory location for theCoach:"+theCoach);
System.out.println("Memory location for alphaCoach:"+alphaCoach);
}
}
true
Memory location for theCoach:com.luv2code.springdemo.TennisCoach@36f0f1be
Memory location for alphaCoach:com.luv2code.springdemo.TennisCoach@36f0f1be
更改scope的方法:
@Component
@Scope("prototype")
public class TennisCoach implements Coach {
每次会创建不同的bean对象:
false
Memory location for theCoach:com.luv2code.springdemo.TennisCoach@ca263c2
Memory location for alphaCoach:com.luv2code.springdemo.TennisCoach@589b3632