六、对象的生命周期

2年前 (2022) 程序员胖胖胖虎阿
342 0 0

一、什么是对象的生命周期?

指的是一个对象创建、存活、消亡的一个完整过程

二、为什么要学习对象的生命周期?

对象的创建在代码层面是简单的,但是从宏观的内存占用的角度上来看,它影响到整个
程序的运行,这里就会涉及到一些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()
版权声明:程序员胖胖胖虎阿 发表于 2022年10月28日 下午8:00。
转载请注明:六、对象的生命周期 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...