一、什么是对象的生命周期?
指的是一个对象创建、存活、消亡的一个完整过程
二、为什么要学习对象的生命周期?
对象的创建在代码层面是简单的,但是从宏观的内存占用的角度上来看,它影响到整个
程序的运行,这里就会涉及到一些JVM和GC回收机制的问题了
总之,由Spring负责对象的创建、存活、销毁,了解生命周期,有利于我们使用好Spring为我们创建的对象
三、生命周期的三个阶段
- 创建阶段
3.1 Spring工厂何时创建对象?
scope=“singleton”
当在Spring标签中定义scope的属性为singleton的时候,该bean对象会在Spring工厂创建
的同时将bean对象创建起来
即当运行了该段代码即会创建=》ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
具体我们怎么判断呢?我们可以在类的无参构造中打印一句话来看是否有创建
scope="prototype"
当设置为原型模式的时候,只有当Spring工厂在获取对象的同时才会创建对象
即当运行这行代码的时候才会创建=》ctx.getBean("")
注意:只有当创建模式选择为单例singleton的时候,如果我们不希望它跟随sprig工厂的创建而创建,那么我们可以通过bean标签的 lazy-init 属性来进行配置,当该lazy属性为true的时候,那么就只有通过Spring工厂获取对象(即getBean()方法被调用),该对象才会被创建
- 初始化阶段
什么是初始化?通俗点理解就是Spring在创建完bean对象后,还需要做一些动作使得这个bean完善起来,具体的内容需要程序员自己去定义,Spring只是提供这个可能性,就犹如父母把你生下来,你还没有完善的,需要经历一些东西,才逐渐完善起来
下面是比较正式的解释:
在初始化阶段中,Spring工厂在创建完对象后,调用对象的初始化方法,完成对应的初始化操作
1.初始化方法的提供:程序员根据需求提供
2.初始化方法调用:Spring工厂进行调用
实现初始化的形式
1> 实现 InitializingBean 接口,重写 afterPropertiesSet() 方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("调用LifeInit初始化方法中........");
}
2>自己提供一个普通方法,但是需要在配置文件中自己定义
public class LifeInit{
public LifeInit() {
System.out.println("正在创建LifeInit对象");
}
//2.自定义初始化方法,在配置文件中配置对应的参数告知spring回调即可
public void myInit(){
System.out.println("(自定义初始化方法)调用LifeInit初始化方法中........");
}
}
自定义bean标签,并声明init-method参数属性,值为初始化方法的名称
<!--自定义初始化方法-->
<bean id="lifeInit" class="cn.paul.spring.demo.hellospring.life.LifeInit"
init-method="myInit"/>
3>*两种形式的对比
实现接口的方式和Spring框架是耦合的关系(因为该接口是Spring提供的),它方便就方便在不需要在配置文件的层面做什么声明,第二种形式就是比较传统的,但是多做一步就是需要在配置文件中配置对应的属性
4>细节分析
4.1 如果一个对象不仅实现了InitializingBean接口同时又提供 普通的初始化方法,Spring的调用顺序是如何呢?
回答:它会先调用InitializingBean重写的方法,然后再调用自定义的初始化方法
这个结合生活经验也很好理解,因为毕竟是用spring嘛
4.2 如果有注入,那么注入是发生在初始化之前还是初始化之后呢?
回答:发生在调用初始化方法之前
结合生活经验:有了一些与生俱来的东西,比如五脏六腑,后续才能对人的各方面有所完善
4.3 在什么场景会用到初始化操作?
其实在业务编程的角度,用到初始化的时机不多,一般用到的都是一些关于资源的初始化
比如:数据库 IO 网络 这些只会做一次的操作(其实这些操作也可以放在注入阶段)
4.4 结合下面的类的代码,说说调用顺序是怎样的?
public class LifeInit implements InitializingBean{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("Spring正在对于LifeBean的name属性进行注入....");
this.name = name;
}
public LifeInit() {
System.out.println("正在创建LifeInit对象");
}
//1.重写接口提供的方法让Spring进行接口回调该方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("调用LifeInit初始化方法中........");
}
//2.自定义初始化方法,在配置文件中配置对应的参数告知spring回调即可
public void myInit(){
System.out.println("(自定义初始化方法)调用LifeInit初始化方法中........");
}
}
上面的代码执行顺序为:
①无参构造 =》②set注入 =》③afterPropertiesSet()方法初始化 =》④myInit()自定义方法初始化
- 销毁阶段
Spring销毁对象前,会调用对象的销毁方法,完成销毁操作,注意是【前】
1.Spring什么时候销毁所创建的对象?
当我们调用ctx.close()来关闭工厂的时候,就会对对象进行销毁
2.销毁方法谁定义,谁调用?
销毁方法是程序员定义的,但是是由Spring来调用的
销毁方法的形式(与初始化方法类似)有哪些?
1.让类实现disposableBean接口
public class LifeInitAndDestroy implements InitializingBean, DisposableBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("Spring正在对于LifeBean的name属性进行注入....");
this.name = name;
}
public LifeInitAndDestroy() {
System.out.println("正在创建LifeInit对象");
}
//1.重写接口提供的方法让Spring进行接口回调该方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("调用LifeInit初始化方法中........");
}
//2.自定义初始化方法,在配置文件中配置对应的参数告知spring回调即可
public void myInit(){
System.out.println("(自定义初始化方法)调用LifeInit初始化方法中........");
}
@Override
public void destroy() throws Exception {
System.out.println("(Spring调用)销毁对象前的操作。。。。");
}
}
2.定义一个普通方法,但是在配置文件的标签层面告知Spring这是一个对象销毁的方法
1.在类中定义普通方法
public class LifeInitAndDestroy implements InitializingBean, DisposableBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("Spring正在对于LifeBean的name属性进行注入....");
this.name = name;
}
public LifeInitAndDestroy() {
System.out.println("正在创建LifeInit对象");
}
//1.重写接口提供的方法让Spring进行接口回调该方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("调用LifeInit初始化方法中........");
}
//2.自定义初始化方法,在配置文件中配置对应的参数告知spring回调即可
public void myInit(){
System.out.println("(自定义初始化方法)调用LifeInit初始化方法中........");
}
@Override
public void destroy() throws Exception {
System.out.println("(Spring调用)销毁对象前的操作。。。。");
}
//3. 自定义销毁方法
public void myDestroy(){
System.out.println("(自定义)销毁对象前的操作。。。。");
}
}
2.在bean标签中说明对应的销毁方法
<bean id="lifeInit" class="cn.paul.spring.demo.hellospring.life.LifeInitAndDestroy"
init-method="myInit" destroy-method="myDestroy">
<property name="name" value="测试初始化bean"/>
</bean>
说明: 与初始化阶段类似,初始化阶段是为了实现一些资源的加载,那么销毁阶段就是为了实现一些资源的释放;
- 细节分析
1.销毁方法的操作只适用于 scope= "singleton",如果为prototype是不调用销毁方法的
如果对于初始化方法,不管是singleton还是prototype都是会调用的(记得是ctx.getBean()哦)
2.什么时候会用到销毁操作呢?
主要涉及到一些资源的释放操作,比如:io.close(),connection.close()