Java 中的公共类称之为 Bean 或 Java Bean,而 Spring 中的 Bean 指的是将对象的生命周期,交个 Spring IoC 容器来管理的对象。所以 Spring 中的 Bean 对象在使用时,无需通过 new 来创建对象,只需要通过 DI(依赖注入),从 Spring 中取出要使用的对象即可。

那么 Spring 中,Bean 的生命周期又有哪些呢?接下来,我们一起来看。

1.Bean 生命周期

Spring 中 Bean 的生命周期是指:Bean 在 Spring(IoC)中从创建到销毁的整个过程。

Spring 中 Bean 的生命周期主要包含以下 5 部分:

  1. 实例化:为 Bean 分配内存空间;
  2. 设置属性:将当前类依赖的 Bean 属性,进行注入和装配;
  3. 初始化:
    1. 执行各种通知;
    2. 执行初始化的前置方法;
    3. 执行初始化方法;
    4. 执行初始化的后置方法。
  4. 使用 Bean:在程序中使用 Bean 对象;
  5. 销毁 Bean:将 Bean 对象进行销毁操作。

以上生命周期中,需要注意的是:“实例化”和“初始化”是两个完全不同的过程,千万不要搞混,实例化只是给 Bean 分配了内存空间,而初始化则是将程序的执行权,从系统级别转换到用户级别,并开始执行用户添加的业务代码

2.代码演示

接下来我们使用代码的方式在 Spring Boot 中,给大家演示一下 Bean 的生命周期。

PS:因为 Spring Boot 是基于 Spring 创建的,所以 Bean 在 Spring 或 Spring Boot 中的行为都是一致的,而 Spring Boot 又是目前主流的框架,所以本文使用 Spring Boot 来演示 Bean 的生命周期。

首先,我们创建一个 Bean 对象,起名为 BeanLifeComponent(类命无所谓,可随意指定),它的具体实现代码如下:

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.stereotype.Component; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; @Component
public class BeanLifeComponent implements BeanNameAware {
public void setBeanName(String s) {
System.out.println("执行 BeanName 的通知方法");
} @PostConstruct
public void postConstruct() {
System.out.println("执行初始化方法");
} public void use() {
System.out.println("使用 Bean");
} @PreDestroy
public void preDestroy() {
System.out.println("执行销毁方法");
}
}

然后,我们再创建一个 MyBeanPostProcessor 类(类命无所谓,可随意指定),来实现初始化的前置方法和初始化的后置方法,具体实现代码如下:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component; @Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("beanLifeComponent")) {
System.out.println("执行初始化前置方法");
}
return bean;
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("beanLifeComponent")) {
System.out.println("执行初始化后置方法");
}
return bean;
}
}

为什么要创建一个单独的类来执行初始化的前置方法和初始化的后置方法呢?

这是因为初始化的前置方法和后置方法是为所有 Bean 服务的,而非为某一个 Bean 服务的,所以这两个方法不能写在某个具体的 Bean 中,否则(这两个方法)不会执行。

最后,在 Spring Boot 的启动类中获取 Bean,具体实现代码如下:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext; @SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
// 得到上下文对象,并启动 Spring Boot 项目
ConfigurableApplicationContext context =
SpringApplication.run(DemoApplication.class, args);
// 获取 Bean
BeanLifeComponent component = context.getBean(BeanLifeComponent.class);
// 使用 Bean
component.use();
// 停止 Spring Boot 项目
context.close();
}
}

以上程序最终的执行结果如下图所示:



从上面的执行结果可以看出,代码执行顺序符合 Bean 生命周期的执行顺序:

  1. 实例化:为 Bean 分配内存空间;
  2. 设置属性:将当前类依赖的 Bean 属性,进行注入和装配;
  3. 初始化:
    1. 执行各种通知;
    2. 执行初始化的前置方法;
    3. 执行初始化方法;
    4. 执行初始化的后置方法。
  4. 使用 Bean:在程序中使用 Bean 对象;
  5. 销毁 Bean:将 Bean 对象进行销毁操作。

那么问题来了,能不能先执行初始化再执行设置属性呢?也就是将生命周期中的步骤 2 和步骤 3 的执行顺序交换一下?

答案是否定的。想象一个场景,如果在初始化方法中要用到被注入对象的某个方法,比如以下代码:

@Controller
public class UserController {
@Resource
private UserService userService; @PostConstruct // 初始化方法
public void postConstruct() {
userService.sayHi();
}
}

此时如果先执行步骤 2,先将 UserService 注入到当前类,再调用步骤 3 执行初始化,那么程序的执行是正常的。然而如果将交互步骤 2 和步骤 3 的执行顺序,那么程序执行就会报错(空指针异常),所以 Bean 的生命周期的顺序必须是:

1.实例化:为 Bean 分配内存空间;

2.设置属性:将当前类依赖的 Bean 属性,进行注入和装配;

3.初始化:

  1. 执行各种通知;
  2. 执行初始化的前置方法;
  3. 执行初始化方法;
  4. 执行初始化的后置方法。

    4.使用 Bean:在程序中使用 Bean 对象;

    5.销毁 Bean:将 Bean 对象进行销毁操作。

总结

Bean 的生命周期指的是 Bean 在 Spring(IoC)中从创建到销毁的整个过程。Bean 的生命周期主要包含以下 5 个流程:

1.实例化:为 Bean 分配内存空间;

2.设置属性:将当前类依赖的 Bean 属性,进行注入和装配;

3.初始化:

  1. 执行各种通知;
  2. 执行初始化的前置方法;
  3. 执行初始化方法;
  4. 执行初始化的后置方法。

    4.使用 Bean:在程序中使用 Bean 对象;

    5.销毁 Bean:将 Bean 对象进行销毁操作。

是非审之于己,毁誉听之于人,得失安之于数。

公众号:Java面试真题解析

面试合集:https://gitee.com/mydb/interview

面试突击80:说一下 Spring 中 Bean 的生命周期?的更多相关文章

  1. 如果你每次面试前都要去背一篇Spring中Bean的生命周期,请看完这篇文章

    前言 当你准备去复习Spring中Bean的生命周期的时候,这个时候你开始上网找资料,很大概率会看到下面这张图: 先不论这张图上是否全面,但是就说这张图吧,你是不是背了又忘,忘了又背? 究其原因在于, ...

  2. JAVA面试题:Spring中bean的生命周期

    Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一 ...

  3. 简:Spring中Bean的生命周期及代码示例

    (重要:spring bean的生命周期. spring的bean周期,装配.看过spring 源码吗?(把容器启动过程说了一遍,xml解析,bean装载,bean缓存等)) 完整的生命周期概述(牢记 ...

  4. 深入理解Spring中bean的生命周期

    [Spring中bean的生命周期] bean的生命周期 1.以ApplocationContext上下文单例模式装配bean为例,深入探讨bean的生命周期: (1).生命周期图: (2).具体事例 ...

  5. Spring中Bean的生命周期及其扩展点

    原创作品,可以转载,但是请标注出处地址http://www.cnblogs.com/V1haoge/p/6106456.html Spring中Bean的管理是其最基本的功能,根据下面的图来了解Spr ...

  6. 通过BeanPostProcessor理解Spring中Bean的生命周期

    通过BeanPostProcessor理解Spring中Bean的生命周期及AOP原理 Spring源码解析(十一)Spring扩展接口InstantiationAwareBeanPostProces ...

  7. 一分钟掌握Spring中bean的生命周期!

    Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean 的别名只能维持 ...

  8. Spring中bean的生命周期!

    Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一 ...

  9. Spring中 bean的生命周期

    为什么要了解Spring中 bean的生命周期? 有时候我们需要自定义bean的创建过程,因此了解Spring中 bean的生命周期非常重要. 二话不说先上图: 在谈具体流程之前先看看Spring官方 ...

随机推荐

  1. Windows 2008R2 IIS环境配置(靶机)

    一.Windows 2008 R2系统安装 VMware Workstation 15安装包 链接:https://pan.baidu.com/s/11sYcZTYPqIV-pyvzo7pWLQ 提取 ...

  2. 如何写好测试用例以及go单元测试工具testify简单介绍

    背景 ​ 最近在工作和业余开源贡献中,和单元测试接触的比较频繁.但是在这两个场景之下写出来的单元测试貌似不太一样,即便是同一个代码场景,今天写出来的单元测试和昨天写的也不是很一样,我感受到了对于单元测 ...

  3. linux目录结构及定时任务

    1. Linux的根目录(最顶层的目录) windows系统有根目录:c盘的根目录就是c:\ d盘的根目录就是d:\ 每个盘(分区)都有自己的根目录 Linux系统, 也支持多个分区 Linux的分区 ...

  4. MySQL查询为什么没走索引?这篇文章带你全面解析

    工作中,经常遇到这样的问题,我明明在MySQL表上面加了索引,为什么执行SQL查询的时候却没有用到索引? 同一条SQL有时候查询用到了索引,有时候却没用到索引,这是咋回事? 原因可能是索引失效了,失效 ...

  5. Detecting Rumors from Microblogs with Recurrent Neural Networks(IJCAI-16)

    记录一下,很久之前看的论文-基于RNN来从微博中检测谣言及其代码复现. 1 引言 现有传统谣言检测模型使用经典的机器学习算法,这些算法利用了根据帖子的内容.用户特征和扩散模式手工制作的各种特征,或者简 ...

  6. 【跟着大佬学JavaScript】之lodash防抖节流合并

    前言 前面已经对防抖和节流有了介绍,这篇主要看lodash是如何将防抖和节流合并成一个函数的. 初衷是深入lodash,学习它内部的好代码并应用,同时也加深节流防抖的理解.这里会先从防抖开始一步步往后 ...

  7. gpg加解密异常

    在本地windows电脑和开发环境(linux) ,都不报错,但是在测试环境(linux) 上报错. 报错信息 org.bouncycastle.openpgp.PGPException: Excep ...

  8. java通过注解顺序通过映射导出excel

    import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.ann ...

  9. Maven3 入门到入门

    Maven3 Core Overview Maven是一个项目管理工具,它包含了一个项目对象模型(Project Object Model,POM) ,一组标准集合,一个项目生命周期(Project ...

  10. python type 与 metaclass理解

    简介 众所周知,type在一般情况下,我们都会去获取一个对象的类型,然后进行类型的比较:除此之外,type还有一个不为人知的作用:动态的创建类.在了解这个之前,首先了解以下type和isinstanc ...