一文读懂 Bean的生命周期

简介: 一文读懂 Bean的生命周期

前言:

日月更替,周而复始,大自然中的任何生命都有着它的周期,比如蚂蚁的寿命只有几年,而乌龟的寿命却有几十年甚至上百年。


同理,在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的构造过程:

  1.  Spring 对bean 进行实例化。
  2.  Spring 将值和bean的引用注入到bean对应的属性中。
  3.  如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBean-Name()  方法。       (实现BeanNameAware清主要是为了通过Bean的引用来获得Bean的ID,一般业务中是很少有用到Bean的ID的)
  4.  如果bean 实现了BeanFactoryAware接口,Spring将调用setBeanFactory() 方法,将BeanFactory容器实例传入。     (实现BeanFactoryAware 主要目的是为了获取Spring容器,如Bean通过Spring容器发布事件等)
  5.  如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext() 方法,将bean所在的应用上下文的引用传入进来。(作用与BeanFactory类似都是为了获取Spring容器,不同的是Spring容器在调用setApplicationContext方法时会把它自己作为setApplicationContext 的参数传入,而Spring容器在调用setBeanDactory前需要程序员自己指定(注入)setBeanDactory里的参数BeanFactory )
  6.  如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessBeforeInitialization() 方法     (作用是在Bean实例创建成功后对进行增强处理,如对Bean进行修改,增加某个功能)
  7.  如果bean实现了InitializingBean接口,Spring将调用它们的after-PropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用。
  8.  如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessAfterInitialization() 方法。    (作用与6的一样,只不过6是在Bean初始化前执行的,而这个是在Bean初始化后执行的,时机不同 )
  9.  此时, bean 已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁。
  10.  如果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走:

   好啦,今天的分享就到这了,希望能够帮到你呢!😊😊  

目录
相关文章
|
存储 Kubernetes NoSQL
无锁队列实现及使用场景
无锁队列实现及使用场景
|
消息中间件 存储 Kafka
RocketMQ 工作原理图解,看这篇就够了!
本文详细解析了 RocketMQ 的核心架构、消息领域模型、关键特性和应用场景,帮助深入理解消息中间件的工作原理。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
RocketMQ 工作原理图解,看这篇就够了!
|
2月前
|
监控 JavaScript Java
基于springboot的游乐园管理系统
本系统基于SpringBoot与Vue技术,构建高效、智能的游乐园管理系统,实现票务电子化、设备监控智能化、员工管理自动化,提升运营效率与游客体验,推动游乐园数字化转型与智慧升级。
|
11月前
|
存储 网络协议 Nacos
高效搭建Nacos:实现微服务的服务注册与配置中心
Nacos(Dynamic Naming and Configuration Service)是阿里巴巴开源的一款动态服务发现、配置管理和服务管理平台。它旨在帮助开发者更轻松地构建、部署和管理分布式系统,特别是在微服务架构中。
1865 82
高效搭建Nacos:实现微服务的服务注册与配置中心
|
安全 应用服务中间件 Apache
Apache-Tomcat-Ajp文件读取漏洞(CVE-2020-1938、CNVD-2020-10487)
Apache-Tomcat-Ajp文件读取漏洞产生原因是由于Tomcat默认开启的AJP服务(8009端口)存在一处文件包含缺陷,攻击者可构造恶意的请求包进行文件包含操作,进而读取受影响Tomcat服务器上的Web目录文件
1455 1
|
JavaScript 前端开发 easyexcel
基于SpringBoot + EasyExcel + Vue + Blob实现导出Excel文件的前后端完整过程
本文展示了基于SpringBoot + EasyExcel + Vue + Blob实现导出Excel文件的完整过程,包括后端使用EasyExcel生成Excel文件流,前端通过Blob对象接收并触发下载的操作步骤和代码示例。
2603 0
基于SpringBoot + EasyExcel + Vue + Blob实现导出Excel文件的前后端完整过程
|
SQL Shell 数据库
MSSQL绕过微软杀毒提权案例
MSSQL绕过微软杀毒提权案例
525 0
|
Linux 开发工具 git
pip的常用命令和常见问题的解决
当使用pip命令安装Python包时,有时候可以通过使用镜像地址来加速下载速度或解决访问限制的问题。以下是一些常用的pip命令和常见的镜像地址:
1660 3
|
Linux 网络安全 Apache
Redhat 9 搭建Apache服务
Apache HTTP Server,开源且广泛使用的Web服务器,以其高效、可靠和可扩展性著称。它有两种工作模式:prefork(多进程单线程)和worker(多进程多线程)。在Redhat 9.2系统上安装Apache,涉及安装httpd服务及相关依赖,配置文件位于`/etc/httpd/conf/httpd.conf`。安装后,需关闭防火墙和SELinux,重启服务并设置开机启动,确保80端口监听。最后,通过IP地址访问测试页面以验证配置成功。
464 0
Redhat 9 搭建Apache服务
|
小程序 Ubuntu Linux
PXE高效批量网络装机
PXE高效批量网络装机