Spring Bean的作用域和生命周期
1.什么是Spring Bean
Spring Bean就会由Spring IOC容器初始化、装配及管理的对象,除此之外,它就和应用程序中其他对象没什么区别了。
2.Spring Bean作用域
2.1 Spring Bean的五种作用域
在创建Spring Bean的时候可以灵活地选择这个对象的作用域,而不用在java类中进行定义。主要支持的五中作用域如下:
类别 | 说明 |
---|---|
singleton | 默认值,Bean以单例的形式存在。即这个Bean在Spring IOC容器中仅存在一个实例。 |
prototype | 这个Bean可以有多个实例,即每次从容器中调用Bean时,都会返回一个新的实例 |
request | 每次 http 请求都会创建一个 bean,该作用域仅在基于 web的Spring ApplicationContext情形下生效 |
session | 同一个Http Sessio共享一个Bean,不同的Session使用的是不同的实例,该作用域仅在基于 web 的Spring ApplicationContext 情形下有效 |
global-session | 在一个全局的 HTTP Session 中,一个 bean 定义对应一个实例。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。 |
- singleton
唯一Bean实例。缺省的 Spring bean 的作用域是 Singleton。Sping Bean默认的作用域是singleton。当一个bean的作用域是singleton时,Spring IOC容器中就会只有一个共享的该bean的实例。所有对该bean的请求得到的也会是同一个对象。singleton分为**懒汉模式**
和**饿汉模式**
:
饿汉模式: 默认,启动容器时(即实例化容器时),为所有spring配置文件或注解定义的bean都生成一个实例
懒汉模式: 在第一次被请求时才会生成实例,以后的请求都调用这个实例。spring singleton设置为懒汉模式:
1.<beans default-lazy-init="true">
- prototype
每次请求都会创建一个新的Bean实例。当一个bean的作用域是prototype时,表示一个bean对应多个实例。prototype是原型类,在创建容器的时候并没有进行实例化,而是程序中需要获取bean的时候才会去实例化。每次对该 bean 请求(即将其注入到另一个 bean 中,或者以程序方法调用IOC容器的 getBean() 方法)时都会创建一个新的 bean 实例,获取到的对象都不是同一个对象。
对有状态的 bean(非线程安全) 应该使用 prototype 作用域,
而对无状态的 bean (线程安全)则应该使用 singleton 作用域
将bean 的作用域定义成 prototype 的几种方式:
1.@scope("prototype")
2.<bean id="xxx" class="com.xx.xxx" scope="prototype"/>
3.<bean id="xxx" class="com.xx.xxx" singleton="false"/>
2.2 Spring bean作用域为什么默认是单例
一个bean创建的时候会先判断作用域是单例(singleton)还是原型(prototype),如果是单例则会先从缓存中获取,如果获取不到再新建,新建的就会存在于缓存中,如果是原型的时候就会新创建一个bean实例。
所以一个bean的作用域为singleton时,在处理请求时,spring容器中只会实例化一个bean,并存在于缓存中,后续的请求都会从缓存中拿到这个bean实例,公用这个实例。prototype则是每次请求都会实例化一个新的bean。
综上:Spring为什么把bean设计成单例的:
1.减少新创建实例的消耗,减少内存分配。
2.新生成的bean少了,jvm垃圾回收的对象也少了。
2.从缓存中拿取bean实例更快。
当然,单例bean也有他的缺点,对于有状态的bean如果是单例的且在多线程环境下就会有线程安全问题。
问题:Spring的Controller是单例还是多例?怎么保证并发的安全
答:单例
怎么保证并发的安全?
1.不要在controller中定义成员变量。
2.万一必须要定义一个非静态成员变量时候,则通过注解@Scope(“prototype”),将其设置为多例模式。
3.在Controller中使用ThreadLocal变量。
3.Spring Bean的生命周期
先看一张图(图片来源自网络)
3.1 完整周期
先来看详细周期,后面为了方便理解和记忆会结合源码进行总结。
1.Spring启动,通过配置文件或注解找到被Spring管理的bean,并加载,然后实例化,相当于常说的new。
————————————————————————————————————————
2.Spring 根据 bean 的定义填充所有的属性。也就是IOC注入。
————————————————————————————————————————
3.BeanNameAware 实现:如果这个 Bean 实现了 BeanNameAware 接口,会调用它的 setBeanName(String)方法,把spring配置文件中bean的id传过来。
4.BeanFactoryAware 实现:如果bean实现了BeanFactoryAware接口,就会调用setBeanFactory(BeanFactory)方法,注入当前的BeanFactory的引用
5.ApplicationContextAware接口实现:如果这个bean实现了该接口,会调用
setApplicationContext(ApplicationContext)方法,传入 Spring 上下文(注入ApplicationContext容器本身,有和4一样的作用,但比效果 4 好,因为 ApplicationContext 是 BeanFactory 的子接口,有更多的实现方法)。
6.BeanPostProcessor接口实现:前置处理,在bean初始化之前,如果已经实现了该接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,这个一般被用作 Bean 内容的更改。
7.InitializingBean接口实现:如果实现了该接口,spring会调用afterPropertiesSet()方法,如果有自定义的init-method方法(Spring允许我们创建自己的 init 方法和 destroy 方法),则执行。
8.BeanPostProcessor 接口实现:后置处理,在初始化之后的后置操作如果这个 Bean 实现了 BeanPostProcessor 接口,将会调用postProcessAfterInitialization(Object obj, String s)方法。
————————————————————————————————————————
9.现在,Bean已经准备好了,可以使用啦,但在使用之前还会注册Destruction(销毁)相关回调接口。
10:最后销毁时如果bean实现了DisposableBean接口,Spring将执行destory()方法,和7一样,如果有自定义的destory-method 方法,该方法也会被执行。
3.2 概括生命周期的流程
看了上面的10个步骤是不是感觉很难记,而且不理解…(其实上面的一些接口平时应该也很少用到)
为了方便学习和记忆可以将上述过程分为4个阶段:
- ①实例化 Instantiation(第1步)
- ②属性赋值 Populate(第2步)
- ③初始化 Initialization(第3~8步)
- ④销毁 Destruction(第9~10步)
这里第9步时使用,实际上还不算是正式的销毁,因为这时还没开始使用或正在使用中。
结合源码加深理解和记忆
① 在方法org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
里可以看到Spring一次执行了这四个阶段(代码中加注释的地方)
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
//*********1.实例化**********
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
Object exposedObject = bean;
try {
//********** 2.属性赋值 **********
this.populateBean(beanName, mbd, instanceWrapper);
//**********3.初始化******************
if (exposedObject != null) {
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
}
} catch (Throwable var18) {
if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
throw (BeanCreationException)var18;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
}
try {
//*********** 4.注册回调接口--销毁**************
this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
} catch (BeanDefinitionValidationException var16) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
}
}
为了直观,中间有的代码省略了没有贴过来。
② 查看第三步中的初始化方法(注释内容:对应上面的步骤序号)
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
// Aware相关接口及操作(对应第3~5)
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
AbstractAutowireCapableBeanFactory.this.invokeAwareMethods(beanName, bean);
return null;
}
}, this.getAccessControlContext());
} else {
this.invokeAwareMethods(beanName, bean);
}
// BeanPostProcessor接口 前置处理(对应第六步)
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
}
// 检查如果实现了InitializingBean,调用它的afterPropertiesSet()方法,
//如果有自定义的init-method方法,则使用(第7步)
try {
this.invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable var6) {
throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
}
// BeanPostProcessor接口 后置处理 (第八步)
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
② 销毁(和第7步类似)
//org.springframework.beans.factory.support.DisposableBeanAdapter#destroy
public void destroy() {
if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
Iterator var1 = this.beanPostProcessors.iterator();
while(var1.hasNext()) {
DestructionAwareBeanPostProcessor processor = (DestructionAwareBeanPostProcessor)var1.next();
processor.postProcessBeforeDestruction(this.bean, this.beanName);
}
}
if (this.invokeDisposableBean) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'");
}
try {
//如果bean实现了DisposableBean接口,Spring将执行destory()方法
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
((DisposableBean)DisposableBeanAdapter.this.bean).destroy();
return null;
}
}, this.acc);
} else {
((DisposableBean)this.bean).destroy();
}
} catch (Throwable var3) {
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
logger.warn(msg, var3);
} else {
logger.warn(msg + ": " + var3);
}
}
}
//如果有自定义的destory-method 方法,该方法也会被执行
if (this.destroyMethod != null) {
this.invokeCustomDestroyMethod(this.destroyMethod);
} else if (this.destroyMethodName != null) {
Method methodToCall = this.determineDestroyMethod();
if (methodToCall != null) {
this.invokeCustomDestroyMethod(methodToCall);
}
}
}
3.3 SpringBean 的扩展
上面不是说了很多接口嘛,有InitializingBean,*Aware,BeanPostProcessor,DisposableBean等等,这些接口可实现可不实现,方便我们对Bean做一些扩展操作。
1.InitializingBean接口和init-method,DisposableBean和destroy-method
通过实现InitializingBean接口的afterPropertiesSet()方法和DisposableBean的destroy()方法 或自定义的init-method和destroy-method方法,可以让我们在Bean初始化属性赋值之后和销毁之前做一些操作,比如查看bean的属性值… …
几个例子:
这里使用demoService
作为正在被Spring管理的Bean
①通过实现接口方法(与Spring耦合)
public class demoService implements InitializingBean,DisposableBean {
//实现两个接口并覆写他们的方法,让Spring执行
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("属性设置完成后执行InitializingBean接口的afterPropertiesSet()完成一些操作");
}
@Override
public void destroy() throws Exception {
System.out.println("销毁之前执行DisposableBean 的destroy()完成一些操作");
}
}
②使用注解(好用)
public class demoService {
@PostConstruct
public void initMethod(){
System.out.println("通过@PostConstruct执行一些操作");
}
@PreDestroy
public void destroyMethod(){
System.out.println("通过@PostConstruct执行一些操作");
}
}
③使用配置文件
public class demoService {
public void initMethod() throws Exception {
System.out.println("执行init-method做一些操作");
}
public void destroyMethod() throws Exception {
System.out.println("执行destroy-method做一些操作");
}
}
<bean name="demoService " class="com.service.demoService " init-method="initMethod" destroy-method="destroyMethod"></bean>
3.4 总结
Spring Bean的生命周期:
- 四大阶段:实例化>属性赋值>初始化>销毁
其中初始化阶段的内容比较多,这部分内容主要就是检查是否实现*Aware接口,调用set方法,通过依赖注入的方式,让Bean获取容器自身的一些对象,例如BeanFactoryAware 接口——setBeanFactory(BeanFactory)方法——BeanFactory;检查是否实现BeanPostProcessor接口,在初始化前后进行处理;检查是否实现InitializingBean接口和init-method方法在初始化时进行自定义操作。