前言:
日月更替,周而复始,大自然中的任何生命都有着它的周期,比如蚂蚁的寿命只有几年,而乌龟的寿命却有几十年甚至上百年。
同理,在Spring框架中,Bean对象也有着它的生命周期,然而对于Bean对象的生命周期,我们并不是很清楚,因为Spring帮助我们管理了Bean对象,所以,掌握Bean的生命周期,并知晓Spring在每个阶段为我们做了哪些事情是非常有必要的。
Spring Bean的生命周期,你了解吗!好啦那我们一起来了解Bean生命周期!!!
一.什么是Bean的生命周期
bean的生命周期指的是:bean创建-->初始化-->销毁 的过程,bean的生命周期由容器进行管理,我们可以自定义bean的初始化和销毁方法来满足我们的需求,当容器在bean进行到当前生命周期的时候,来调用自定义的初始化和销毁方法。
在传统的Java应用中,bean的生命周期很简单,使用Java关键字 new 进行Bean 的实例化,然后该Bean 就能够使用了。一旦bean不再被使用,则由Java自动进行垃圾回收。
相比之下,Spring管理Bean的生命周期就复杂多了,正确理解Bean 的生命周期非常重要,因为Spring对Bean的管理可扩展性非常强,下面展示了一个Bean的构造过程:
- Spring 对bean 进行实例化。
- Spring 将值和bean的引用注入到bean对应的属性中。
- 如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBean-Name() 方法。 (实现BeanNameAware清主要是为了通过Bean的引用来获得Bean的ID,一般业务中是很少有用到Bean的ID的)
- 如果bean 实现了BeanFactoryAware接口,Spring将调用setBeanFactory() 方法,将BeanFactory容器实例传入。 (实现BeanFactoryAware 主要目的是为了获取Spring容器,如Bean通过Spring容器发布事件等)
- 如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext() 方法,将bean所在的应用上下文的引用传入进来。(作用与BeanFactory类似都是为了获取Spring容器,不同的是Spring容器在调用setApplicationContext方法时会把它自己作为setApplicationContext 的参数传入,而Spring容器在调用setBeanDactory前需要程序员自己指定(注入)setBeanDactory里的参数BeanFactory )
- 如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessBeforeInitialization() 方法 (作用是在Bean实例创建成功后对进行增强处理,如对Bean进行修改,增加某个功能)
- 如果bean实现了InitializingBean接口,Spring将调用它们的after-PropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用。
- 如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessAfterInitialization() 方法。 (作用与6的一样,只不过6是在Bean初始化前执行的,而这个是在Bean初始化后执行的,时机不同 )
- 此时, bean 已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁。
- 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。
二.Bean的核心生命周期
虽然spring提供了大量Bean级生命周期接口和容器级生命空间接口来扩展bean的生命周期,但bean的核心生命周期只有四个阶段:
1.实例化 Instantiation
doCreateBean中调用createBeanInstance() 方法
2.属性赋值 Populate
doCreateBean中调用populateBean() 方法
3.初始化 Initialization
doCreateBean中调用initializeBean() 方法
4.销毁 Destruction
对于scope=singleton的Bean (prototype不会触发销毁),当容器关闭时,会触发bean的销毁。
三.Bean的单例与多例模式
3.1.什么是单例与多例
在Spring中,bean可以被定义为两种模式:prototype(多例)和singleton(单例)
singleton(单例):只有一个共享的实例存在,所有对这个bean的请求都会返回这个唯一的实例。
prototype(多例):对这个bean的每次请求都会创建一个新的bean实例,类似于new。
Spring bean默认是单例模式。
3.2.单例与多例bean的生命周期
- 单实例下 bean的生命周期
容器启动——>初始化方法——>(容器关闭)销毁方法
- 多实例下 bean的生命周期
容器启动——>调用bean——>初始化方法——>容器关闭(销毁方法不执行)
3.3.单例与多例的演示
单例模式:
package com.junlinyi.beanLife; import java.util.List; public class ParamAction { private int age; private String name; private List<String> hobby; private int num = 1; public ParamAction() { super(); } public ParamAction(int age, String name, List<String> hobby) { super(); this.age = age; this.name = name; this.hobby = hobby; } public void execute() { System.out.println("this.num=" + this.num++); System.out.println(this.name); System.out.println(this.age); System.out.println(this.hobby); } }
测试一手:
package com.junlinyi.beanLife; import org.junit.Test; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; /* * spring bean的生命週期 * spring bean的單例多例 * */ public class Demo2 { // 体现单例与多例的区别 @Test public void test1() { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml"); ParamAction p1 = (ParamAction) applicationContext.getBean("paramAction"); ParamAction p2 = (ParamAction) applicationContext.getBean("paramAction"); p1.execute(); p2.execute(); // 单例时,容器销毁instanceFactory对象也销毁;多例时,容器销毁对象不一定销毁; applicationContext.close(); } }
spring配置文件:
<!-- bean的生命周期--> <bean id="paramAction" class="com.junlinyi.beanLife.ParamAction"> <constructor-arg name="name" value="三丰"></constructor-arg> <constructor-arg name="age" value="21"></constructor-arg> <constructor-arg name="hobby"> <list> <value>抽烟</value> <value>烫头</value> <value>大保健</value> </list> </constructor-arg> </bean> </beans>
结果:
由于我们默认使用的是单例模式,所以在运行时出现了变量污染,num值变为2
Bean工厂:
package com.junlinyi.beanLife; public class InstanceFactory { public void init() { System.out.println("初始化方法"); } public void destroy() { System.out.println("销毁方法"); } public void service() { System.out.println("业务方法"); } }
测试一手:
package com.junlinyi.beanLife; import org.junit.Test; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; /* * spring bean的生命週期 * spring bean的單例多例 * */ public class Demo2 { // 体现单例与多例的初始化的时间点 instanceFactory @Test public void test2() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml"); } }
spring配置上下文:
<bean id="instanceFactory" class="com.junlinyi.beanLife.InstanceFactory" scope="singleton" init-method="init" destroy-method="destroy"></bean>
.单例模式中的JavaBean是跟着Spring上下文初始化的,容器生成对象跟着生成,容器死亡,对象死亡
多例模式:
将spring配置文件中指定scope为prototype
<bean id="paramAction" class="com.junlinyi.beanLife.ParamAction" scope="prototype"> <constructor-arg name="name" value="三丰"></constructor-arg> <constructor-arg name="age" value="21"></constructor-arg> <constructor-arg name="hobby"> <list> <value>抽烟</value> <value>烫头</value> <value>大保健</value> </list> </constructor-arg> </bean> <bean id="instanceFactory" class="com.xissl.beanLife.InstanceFactory" scope="prototype" init-method="init" destroy-method="destroy"></bean>
结果:
多例模式走的Javabean是使用时才会创建,销毁要跟着Jvm走: