八、Bean的生命周期

news2025/1/15 19:45:19

Bean生命周期的管理,可以参考Spring的源码:AbstractAutowireCapableBeanFactory类的doCreateBean()方法。

1 什么是Bean的生命周期

Spring其实就是一个管理Bean对象的工厂。它负责对象的创建,对象的销毁等。
所谓的生命周期就是:对象从创建开始到最终销毁的整个过程。
什么时候创建Bean对象?
创建Bean对象的前后会调用什么方法?
Bean对象什么时候销毁?
Bean对象的销毁前后调用什么方法?

2 为什么要知道Bean的生命周期

生命周期的本质是:在哪个时间节点上调用了哪个类的哪个方法。
我们需要充分的了解在这个生命线上,都有哪些特殊的时间节点。
只有我们知道了特殊的时间节点都在哪,到时我们才可以确定代码写到哪。
我们可能需要在某个特殊的时间点上执行一段特定的代码,这段代码就可以放到这个节点上。当生命线走到这里的时候,自然会被调用。

3 Bean生命周期之5步


Bean生命周期可以粗略的划分为五大步:
  • 第一步:实例化Bean
  • 第二步:Bean属性赋值
  • 第三步:初始化Bean
  • 第四步:使用Bean
  • 第五步:销毁Bean
    在这里插入图片描述
package com.powernode.spring6.bean;
/**
 * Bean的生命周期按照粗略的五步的话:
 * 第一步:实例化Bean(调用无参数构造方法。)
 * 第二步:给Bean属性赋值(调用set方法。)
 * 第三步:初始化Bean(会调用Bean的init方法。注意:这个init方法需要自己写,自己配。)
 * 第四步:使用Bean
 * 第五步:销毁Bean(会调用Bean的destroy方法。注意:这个destroy方法需要自己写,自己配。)
 */
public class User {
    private String name;

    public void setName(String name) {
        System.out.println("第二步,给对象的属性赋值");
        this.name = name;
    }

    public User() {
        System.out.println("第一步,无参数构造方法执行");
    }

    // 这个方法需要自己写,自己配,方法名随意
    public void initBean(){
        System.out.println("第三步,初始化Bean");
    }

    // 这个方法需要自己写,自己配,方法名随意
    public void destroyBean(){
        System.out.println("第五步,销毁Bean");
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--需要手动指定初始化方法和销毁方法-->
    <!--
    init-method属性指定初始化方法。
    destroy-method属性指定销毁方法。
    -->
    <bean id="user" class="com.powernode.spring6.bean.User" init-method="initBean" destroy-method="destroyBean">
        <property name="name" value="张三"/>
    </bean>
</beans>

测试

package com.powernode.spring6.test;

import com.powernode.spring6.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanLifecycleTest {
    @Test
    public void testBeanLifecycleFive(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        User user = applicationContext.getBean("user", User.class);
        System.out.println("第四步,使用Bean:" + user);

        // 手动关闭Spring容器,这样Spring容器才会销毁Bean
        ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
        context.close();
    }
}

在这里插入图片描述

  • 只有正常关闭spring容器,bean的销毁方法才会被调用。
  • ClassPathXmlApplicationContext类才有close()方法。
  • 配置文件中的init-method指定初始化方法。destroy-method指定销毁方法。

4 Bean生命周期之7步

Bean生命周期七步:比五步添加的那两步在哪里?在初始化Bean的前和后。
第一步:实例化Bean
第二步:Bean属性赋值
第三步:执行“Bean后处理器”的before方法。
第四步:初始化Bean
第五步:执行“Bean后处理器”的after方法。
第六步:使用Bean
第七步:销毁Bean

在初始化前和初始化后添加代码,可以加入“Bean后处理器”。

编写一个类实现BeanPostProcessor类,并且重写before和after方法:

package com.powernode.spring6.test;

import com.powernode.spring6.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanLifecycleTest {
    @Test
    public void testBeanLifecycleFive(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        User user = applicationContext.getBean("user", User.class);
        System.out.println("第四步,使用Bean:" + user);

        // 手动关闭Spring容器,这样Spring容器才会销毁Bean
        ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
        context.close();
    }
}

在spring.xml文件中配置“Bean后处理器”:

<!--配置Bean后处理器-->
<!--注意:这个Bean后处理器作用于当前配置文件中所有的bean-->
<bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>

在这里插入图片描述

加上Bean后处理器的话,Bean的生命周期就是7步了:
在这里插入图片描述

5 Bean生命周期之10步

Bean生命周期十步:比七步添加的那三步在哪里?

  • 点位1:在“Bean后处理器”before方法之前
    检查Bean是否实现了Aware相关的接口,如果实现了接口则调用这些接口中的方法。
    然后调用这些方法的目的是为了给你传递一些数据,让你更加方便使用。

  • 点位2:在“Bean后处理器”before方法之后
    检查Bean是否实现了InitializingBean接口,如果实现了,则调用接口中的方法。

  • 点位3:使用Bean之后,或者说销毁Bean之前
    检查Bean是否实现了DisposableBean接口,如果实现了,则调用接口中的方法。

添加的这三个点位的特点:都是在检查你这个Bean是否实现了某些特定的接口,如果实现了这些接口,则Spring容器会调用这个接口中的方法。
在这里插入图片描述


Aware相关的接口包括:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
  • 当Bean实现了BeanNameAware,Spring会将Bean的名字传递给Bean。
  • 当Bean实现了BeanClassLoaderAware,Spring会将加载该Bean的类加载器传递给Bean。
  • 当Bean实现了BeanFactoryAware,Spring会将Bean工厂对象传递给Bean。
package com.powernode.spring6.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;

/**
 * Bean的生命周期按照粗略的五步的话:
 * 第一步:实例化Bean(调用无参数构造方法。)
 * 第二步:给Bean属性赋值(调用set方法。)
 * 第三步:初始化Bean(会调用Bean的init方法。注意:这个init方法需要自己写,自己配。)
 * 第四步:使用Bean
 * 第五步:销毁Bean(会调用Bean的destroy方法。注意:这个destroy方法需要自己写,自己配。)
 */
public class User implements BeanNameAware, BeanFactoryAware, BeanClassLoaderAware, InitializingBean, DisposableBean{
    private String name;

    public void setName(String name) {
        System.out.println("第二步,给对象的属性赋值");
        this.name = name;
    }

    public User() {
        System.out.println("第一步,无参数构造方法执行");
    }

    // 这个方法需要自己写,自己配,方法名随意
    public void initBean(){
        System.out.println("第三步,初始化Bean");
    }

    // 这个方法需要自己写,自己配,方法名随意
    public void destroyBean(){
        System.out.println("第五步,销毁Bean");
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("before方法之前执行 Bean这个类的类加载器:" + classLoader);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("before方法之前执行 生产Bean的工厂对象:" + beanFactory);
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("before方法之前执行 这个Bean的名字:" + name);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("before方法之后执行 InitializingBean的afterPropertiesSet()方法执行");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("销毁Bean之前执行 DisposableBean的destroy()方法执行");
    }
}

在这里插入图片描述

6 Bean的作用域不同,管理方式不同

Spring 根据Bean的作用域来选择管理方式。

  • Spring容器只对singleton的Bean进行完整的生命周期管理。
  • 如果是prototype作用域的Bean,Spring容器只负责将该Bean初始化完毕。等客户端程序一旦获取到该Bean之后,Spring容器就不再管理该对象的生命周期了。

7 自己new的对象如何让Spring管理

java对象是我们自己new的,希望这个对象被Spring容器管理

package com.powernode.spring6.bean;
public class Student {
}
@Test
public void testRegisterBean(){
    // 自己new对象
    Student student = new Student();
    System.out.println(student);

    // 将自己new的对象纳入Spring容器管理
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    // 注册Bean
    factory.registerSingleton("studentBean", student);

    // 从spring容器中获取bean
    Student studentBean = factory.getBean("studentBean", Student.class);
    System.out.println(studentBean);
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/387694.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【SpringCloud】SpringCloud教程之Feign实战

目录前言SpringCloud Feign远程服务调用一.需求二.两个服务的yml配置和访问路径三.使用RestTemplate远程调用(order服务内编写)四.构建Feign(order服务内配置)五.自定义Feign配置(order服务内配置)六.Feign配置日志(oder服务内配置)七.Feign调优(order服务内配置)八.抽离Feign前…

论文投稿指南——中文核心期刊推荐(新闻事业)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

Spring Cloud融合Nacos配置加载优先级 | Spring Cloud 8

一、前言 Spring Cloud Alibaba Nacos Config 目前提供了三种配置能力从 Nacos 拉取相关的配置&#xff1a; A&#xff1a;通过内部相关规则(应用名、扩展名、profiles)自动生成相关的 Data Id 配置B&#xff1a;通过 spring.cloud.nacos.config.extension-configs的方式支持…

Redis十大类型——List常见操作

Redis十大类型——List常见操作 底层数据结构是双端链表 Redis列表是字符串值的链接列表。Redis列表经常用于&#xff1a; 实现堆栈和队列。为后台工作系统构建队列管理。 命令操作简列 lpush &#xff1a; 左侧添加元素rpush &#xff1a; 右侧添加元素lrange &#xff1a; …

LPNet for Image Derain

Lightweight Pyramid Networks for Image Deraining前置知识高斯-拉普拉斯金字塔图像中的高频信息和低频信息为什么高斯-拉普拉斯金字塔可以实现去雨&#xff1f;可能性分析网络结构整体结构&#xff1a;子网结构&#xff1a;递归块结构&#xff1a;后续补充代码 前置知识 这…

数组--java--动态数组--有序数组--底层

java数组基础--java中的数组创建数组空间占用初始化数组访问元素插入查找删除元素动态数组扩容插入和添加重写toString删除二维数组二维数组注意点有序数组实现测试写在开头&#xff1a; 这篇文章包括数组的基础、一点底层的内容和一些稍微深入的东西。 作为第一个深入学习的数…

【2021.12.25】ctf逆向中常见加密算法和编码识别

【2021.12.25】ctf逆向中常见加密算法和编码识别&#xff08;含exe及wp&#xff09; 文章目录【2021.12.25】ctf逆向中常见加密算法和编码识别&#xff08;含exe及wp&#xff09;0、前言1、基础加密手法2、base64&#xff08;1&#xff09;原理&#xff1a;&#xff08;2&#…

利用出厂状态下的闲置主机配置HP M1136打印机

利用出厂状态下的闲置主机配置HP M1136打印机 打印机型号&#xff1a;LaserJet M1136 MFP 主机状态&#xff1a;出厂状态&#xff0c;C盘及储存盘被分成了5片 网络环境&#xff1a;与打印机相连的主机全程无Internet连接&#xff0c;主机处于离线状态。打印机驱动及一些相关软…

Splunk 成功获取Salesforce 数据

1: 先说一下Splunk server 上要安装Splunk Add-on for Salesforce : (https://splunkbase.splunk.com/) 去下载: https://splunkbase.splunk.com/app/3549 2: 下载安装后,看到如下界面: 3: 官方的指导文档: Configure your Salesforce account to collect data…

0301_对应的南京比特物联网

0301_对应的南京比特物联网目录概述需求&#xff1a;设计思路实现思路分析1.流程拓展实现性能参数测试&#xff1a;参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better …

C#的Version类型值与SQL Server中二进制binary类型转换

使用C#语言编写的应用程序可以通过.NET Framework框架提供的Version类来控制每次发布的版本号&#xff0c;以便更好控制每次版本更新迭代。 版本号由两到四个组件组成&#xff1a;主要、次要、内部版本和修订。 版本号的格式如下所示&#xff0c; 可选组件显示在方括号 ([ 和…

UML 时序图

时序图&#xff08;Sequence Diagram&#xff09;是显示对象之间交互的图&#xff0c;是按时间顺序排列的。 时序图中显示的是参与交互的对象及其对象之间消息交互的顺序。 时序图包括的建模元素主要有&#xff1a;对象&#xff08;Actor&#xff09;、生命线&#xff08;Lif…

项目实战典型案例19——临时解决方案和最终解决方案

临时解决方案和最终解决方案一&#xff1a;背景介绍二&#xff1a;思路&方案四&#xff1a;总结五&#xff1a;升华一&#xff1a;背景介绍 本篇博客是对项目开发中出现的临时解决方案和最终解决方案进行的总结和改进。目的是将经历转变为自己的经验。通过博客的方式分享给…

(蓝桥真题)最长不下降子序列(权值线段树)

样例输入&#xff1a; 5 1 1 4 2 8 5 样例输出&#xff1a; 4 分析&#xff1a;看到这种对其中连续k个数进行修改的我们就应该想到答案是由三部分组成&#xff0c;因为求的是最长不下降子序列&#xff0c;那么我们可以找到一个最合适的断点i&#xff0c;使得答案是由区间[1…

【信息安全案例】——网络信息面临的安全威胁

&#x1f4d6; 前言&#xff1a;2010年&#xff0c;震网病毒&#xff08;Stuxnet&#xff09;席卷全球工业界。其目标是从物理上摧毁一个军事目标&#xff0c;这使得网络武器不仅仅只存在于那个人类创造的空间。网络武器的潘多拉魔盒已经打开。 目录&#x1f552; 1. 信息、信息…

28个精品Python爬虫实战项目

先来说说Python的优势&#xff01;然后给大家看下这28个实战项目的实用性&#xff01;Python跟其他语言相比&#xff0c;有以下优点&#xff1a;1. 简单Python是所有编程语言里面&#xff0c;代码量最低&#xff0c;非常易于读写&#xff0c;遇到问题时&#xff0c;程序员可以把…

学习 Python 之 Pygame 开发魂斗罗(八)

学习 Python 之 Pygame 开发魂斗罗&#xff08;八&#xff09;继续编写魂斗罗1. 创建敌人类2. 增加敌人移动和显示函数3. 敌人开火4. 修改主函数5. 产生敌人6. 使敌人移动继续编写魂斗罗 在上次的博客学习 Python 之 Pygame 开发魂斗罗&#xff08;七&#xff09;中&#xff0…

通信网络-Socket、Java中的网络支持、多线程服务器

前言 通信网络-Socket、Java中的网络支持、多线程服务器 场景&#xff1a;使用java网络创建一个聊天室 博客地址&#xff1a;芒果橙的个人博客 文章目录前言通信网络-SocketTCP/IPTCP/IP 模型端口Java中的网络支持概念1. InetAddress2. URL3. Socket4. Datagram多线程服务器应用…

使用ECharts打造一个数据可视化面板

使用ECharts打造一个数据可视化面板1. 使用技术2. 案例适配方案3. 基础设置4. header 布局5. mainbox 主体模块6. 公共面板模块 panel7. 柱形图 bar 模块&#xff08;布局&#xff09;8. 中间布局9. ECharts 介绍10. ECharts 体验11. ECharts 基础配置12. 柱状图图表&#xff0…

MDK软件使用技巧

本文主要汇总MDK软件使用技巧 一、字体大小及颜色修改 第一步点击工具栏的这个小扳手图标 进去后显示如下&#xff0c;先设置 Encoding 为&#xff1a;Chinese GB2312(Simplified)&#xff0c;然后设置 Tab size 为&#xff1a;4 以更好的支持简体中文&#xff0c;否则&…