Bean 的生命周期

什么是Bean的生命周期

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

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

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

Bean的生命周期之5步

  • Bean生命周期的管理,可以参考Spring的源码:AbstractAutowireCapableBeanFactory类的doCreateBean()方法。
  • Bean生命周期可以粗略的划分为五大步:
    • 第一步:实例化Bean,调用无参构造方法创建对象
    • 第二步:Bean属性赋值,调用对象的set方法,进行set注入
    • 第三步:初始化Bean,调用Bean的init方法(该方法需要自己写,然后进行配置)
    • 第四步:使用Bean
    • 第五步:销毁Bean,调用Bean的Destroy方法(该方法需要自己写,然后进行配置)
      • 进行Bean的销毁,必须关闭Spring容器,只有关闭了Spring容器,Bean才会进行销毁

Bean 的编写
package cw.spring.study.pojo;/*** ClassName: User* Package: cw.spring.study.pojo* Description:*/
public class User {private String name;public User() {System.out.println("1. User 无参构造方法执行");}public void setName(String name) {this.name = name;System.out.println("2. User setName 方法执行");}public void init() {System.out.println("3. User init 方法执行,进行 Bean 的初始化");}public void destroy() {System.out.println("5. User destroy 方法执行,进行 Bean 的销毁");}
}
Bean 的配置
<!-- 手动指定Bean的初始化方法和销毁方法init-method 属性配置 Bean 的初始化方法destroy-method配置 Bean 的销毁方法
-->
<bean id="user" class="cw.spring.study.pojo.User" init-method="init" destroy-method="destroy"><property name="name" value="张三"/>
</bean>
测试
@org.junit.Test
public void testUser() {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");User user = applicationContext.getBean("user", User.class);System.out.println("4. User Bean 的使用," + user);// 进行Bean的销毁,必须关闭Spring容器,只有关闭了Spring容器,Bean才会进行销毁// ApplicationContext 接口中无关闭容器的方法,ClassPathXmlApplicationContext 中有声明定义ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;// 关闭容器context.close();
}

Bean生命周期之7步

  • Bean生命周期七步,比Bean生命周期五步,在初始化Bean的前和后,添加了两步。
  • 在以上的5步中,第3步是初始化Bean,在初始化前和初始化后执行的方法为“Bean后处理器”的before和after方法,通过“Bean后处理器”我们可以在初始化Bean的前后添加需要执行的代码。
  • 要添加“Bean后处理器”需要类实现BeanPostProcessor类,并且重写before和after方法
  • Bean生命周期之7步:
    • 第一步:实例化Bean
    • 第二步:Bean属性赋值
    • 第三步:执行“Bean后处理器”的before方法。
    • 第四步:初始化Bean
    • 第五步:执行“Bean后处理器”的after方法。
    • 第六步:使用Bean
    • 第七步:销毁Bean

创建 Bean 后处理器
package cw.spring.study.pojo;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;/*** ClassName: LogBeanPostProcessor* Package: cw.spring.study.pojo* Description:* 日志Bean后处理器,* 在Bean对象的初始化前后执行相应的代码*/
public class LogBeanPostProcessor implements BeanPostProcessor {/*** 初始化Bean之前执行的代码** @param bean 刚创建的Bean* @param beanName Bean的名字* @return* @throws BeansException*/@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("日志 Bean 后处理器的 before 方法执行...");// return 不要修改return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("日志 Bean 后处理器的 after 方法执行...");// return 不要修改return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}
}
配置 Bean 后处理器
  • 在 Spring 的配置文件中配置 Bean 后处理器
  • Bean 后处理器配置完成后,将会作用于整个配置文件中==每个== Bean 的生命周期过程中,如在spring.xml文件中配置的Bean后处理器将会作用于当前配置文件中所有的Bean。
<!-- 配置 Bean 后处理器将会作用于本配置文件中所有Bean对象的生命周期中 
-->
<bean class="cw.spring.study.pojo.LogBeanPostProcessor"/>

测试

Bean生命周期之十步

  • Bean生命周期十步比七步多的三步:
    • 点位1:在“Bean后处理器”before方法之前,在Bean属性赋值之后
    • 点位2:在“Bean后处理器”before方法之后,在Bean的初始化之前
    • 点位3:使用Bean之后,或者说销毁Bean之前
  • 添加的这三个点位的特点:都是在检查你这个Bean是否实现了某些特定的接口,如果实现了这些接口,则Spring容器会调用这个接口中的方法。

实现 Aware 相关接口

Aware相关的接口包括:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware

  • 当Bean实现了BeanNameAware,Spring会将Bean的名字传递给Bean。
  • 当Bean实现了BeanClassLoaderAware,Spring会将加载该Bean的类加载器传递给Bean。
  • 当Bean实现了BeanFactoryAware,Spring会将Bean工厂对象传递给Bean。

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

package cw.spring.study.pojo;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;/*** ClassName: User* Package: cw.spring.study.pojo* Description:*/
public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {private String name;public User() {System.out.println("1. User 无参构造方法执行");}public void setName(String name) {this.name = name;System.out.println("2. User setName 方法执行");}public void init() {System.out.println("4. User init 方法执行,进行 Bean 的初始化");}public void destroy() {System.out.println("7. User destroy 方法执行,进行 Bean 的销毁");}@Overridepublic void setBeanClassLoader(ClassLoader classLoader) {System.out.println("User Bean 的类加载器:" + classLoader);}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {System.out.println("生产 User Bean 的工厂:" + beanFactory);}@Overridepublic void setBeanName(String name) {System.out.println("User Bean 的名字为:" + name);}
}

实现 InitializingBean 接口
  • 在Bean初始化之前,检查Bean是否实现了InitializingBean接口,如果实现了,则调用接口中的方法。
  • InitializingBean的方法早于init-method的执行。
public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean {...@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("InitializingBean 的 afterPropertiesSet 方法执行...");}
}

实现 DisposableBean 接口
  • 在销毁Bean之前,检查Bean是否实现了DisposableBean接口,如果实现了,则调用接口中的方法。
  • DisposableBean的方法早于destroy-method的执行.
public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware,InitializingBean, DisposableBean {...@Overridepublic void destroy() throws Exception {System.out.println("DisposableBean destroy 方法执行...");}// 之前销毁Bean的方法与DisposableBean接口中的方法重名,// 进行销毁方法名的修改,并修改Spring.xml文件中的配置public void myDestroy() {System.out.println("7. User destroy 方法执行,进行 Bean 的销毁");}...}

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

  • Spring 会根据Bean的作用域来选择管理方式
  • 对于singleton作用域的Bean,Spring 能够精确地知道该Bean何时被创建,何时初始化完成,以及何时被销毁;而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,对该Bean初始化完毕,等到客户端程序获取到该Bean之后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。
  • Spring容器只对singleton的Bean进行完整的生命周期管理,对于prototype的Bean,Spring只进行部分的生命周期管理。

<?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"><!-- 配置 Bean 后处理器 --><bean class="cw.spring.study.pojo.LogBeanPostProcessor"/><bean id="user" class="cw.spring.study.pojo.User" init-method="init" destroy-method="myDestroy"scope="prototype"><property name="name" value="张三"/></bean></beans>

将自己 new 的对象交给 Spring 管理

  • 有些时候可能会遇到这样的需求,某个java对象是我们自己new的,然后我们希望这个对象被Spring容器管理这时候就可以用DefaultListableBeanFactory中的registerSingleton方法

public class Student {}

@org.junit.Test
public void testRegisterBean() {Student student = new Student();System.out.println(student);// 将自己new的对象交给Spring进行管理// 使用DefaultListableBeanFactory对象进行Bean实例的注册DefaultListableBeanFactory factory = new DefaultListableBeanFactory();// 将自己new的对象注册到Spring容器中factory.registerSingleton("student", student);// 从Spring容器中获取BeanSystem.out.println(factory.getBean("student"));
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

13-springcloud gateway集成nacos实现负载均衡

网关作为访问系统的入口&#xff0c;负载均衡是必选项而不是可选项&#xff0c;本文介绍gateway与nacos集成&#xff0c;实现负载均衡的过程。关于springcloud gateway的基本用法&#xff0c;同学可以看看上篇文章: 12-使用gateway作为网关。 0、环境 jdk&#xff1a;1.8spri…

idea插件开发的第一天-写一个小Demo

介绍 Demo说明 本文基于maven项目开发,idea版本为2022.3以上,jdk为1.8本文在Tools插件之上进行开发 Tools插件说明 Tools插件是一个Idea插件,此插件提供统一Spi规范,极大的降低了idea插件的开发难度,并提供开发者模块,可以极大的为开发者开发此插件提供便利Tools插件安装需…

LLM系列 | 36:Google最新开源大模型:Gemma 2介绍及其微调(下篇)

引言 环境安装 数据准备 下载 处理 模型训练 模型inference 结果 gemma-2-9b gemma-2-9b-it 引言 低头观落日&#xff0c;引手摘飞星。 小伙伴们好&#xff0c;我是微信公众号《小窗幽记机器学习》的小编&#xff1a;卖黑神话的小女孩。本文紧接前文Google最新开源大…

栈和队列——用队列实现栈

题目中给出&#xff0c;让我们应用两个队列实现栈&#xff0c;首先我们先来想一下&#xff0c;栈是先进后出&#xff0c;队列是先进先出。所以我们就需要应用两个队列来回导才能实现栈的特点。因为这道题是基于队列来实现的&#xff0c;所以在下方若有看不懂的函数名称可以去栈…

【indirect 函数 ★二级下拉菜单】

Indirect 函数 &#x1f33c;indirect函数参数&#x1f33c;应用&#xff1a;&#x1f33c;跨表引用同一单元格&#x1f33c;二级下拉列表 &#x1f33c;indirect函数参数 返回⬅️【文本字符串所指定的引用】 INDIRECT(ref_text,[a1]) 其中【ref_text】是引用的文本 [a1] 是…

网络安全实训六(靶机实例DC-3)

1 信息收集 1.1 获取靶机IP 1.2 扫描靶机网站的目录 1.3 扫描端口和服务器信息 1.4 进入网站 1.5 在msf中给搜索joomla扫描器 1.6 设置参数查看joomla版本信息 1.7 按照版本号搜索漏洞 1.8 查看漏洞使用 2 渗透 2.1 查看是否存在SQL注入 2.2 获取到数据库信息 2.3 爆破列表 2…

盘点java8 stream中隐藏的函数式接口

shigen坚持更新文章的博客写手&#xff0c;记录成长&#xff0c;分享认知&#xff0c;留住感动。个人IP&#xff1a;shigen 提到函数式接口&#xff0c;最常见的就是lambda表达式&#xff0c;IDEA也有智能的提示&#xff1a; 最后改成这样的就是最简洁的、IDEA希望的风格&#…

【我要成为配环境高手】Visual Studio中Qt安装与配置(无伤速通)

1.下载安装Qt和VSIX插件 2.本地环境变量配置 添加如下&#xff1a; D:\ProgramData\Qt\Qt5.14.2\5.14.2\msvc2017_64\libD:\ProgramData\Qt\Qt5.14.2\5.14.2\msvc2017_64\bin3.VS配置 ⭐项目右键->属性->调试->环境&#xff0c;添加如下&#xff1a;(很重要&#x…

随笔十、音频扩展模块测试

本项测试简单&#xff0c;对购买的音频扩展模块进行录音放音测试 按照使用说明&#xff0c;连接音频小板&#xff0c;一个喇叭一个麦克风&#xff0c;4根线&#xff0c;buildroot系统镜像 录音测试 rootRK356X:/# arecord -c 1 -r 44100 -f S16_LE /tmp/record.wav Recording …

【面试五】PID控制算法

一、 PID算法简介 PID&#xff08;Proportional-Integral-Derivative&#xff09;控制算法是一种经典的反馈控制方法&#xff0c;广泛应用于自动控制系统&#xff0c;例如温度控制、速度控制、位置控制等。 PID控制算法的核心包含三个部分&#xff1a;比例项&#xff08;P&…

Linux基础(包括centos7安装、linux基础命令、vi编辑器)

一、安装CentOS7 需要&#xff1a;1、VMware Workstation&#xff1b;2、CentOS7镜像 1、安装镜像 2、虚拟机配置 开启虚拟机&#xff0c;鼠标从vm中移出来用快捷键ctrlalt 点击开始安装&#xff0c;设置密码&#xff0c;等待安装完成,&#xff0c;重启。 3、注意事项 如果没…

CAN总线简介

CAN 是 Controller Area Network 的缩写&#xff08;以下称为 CAN&#xff09;&#xff0c;是 ISO国际标准化的串行通信协议。 历史背景 CAN 最初出现在80年代末的汽车工业中&#xff0c;由德国 Bosch 公司最先提出。当时&#xff0c;由于消费者对于汽车功能的要求越来越多&a…

android仿assistivetouch悬浮窗实现(带功能实现)

一、悬浮窗点击后的界面&#xff1a; 主要有四个功能&#xff0c;返回、应用程序、退出和主界面。其他功能也可以类似添加。 界面布局代码就不贴出来了&#xff0c;源码&#xff08;切记需要签名才能让功能实现&#xff09;&#xff1a;下载地址 二、主要是检测系统启动或者a…

动态规划法例题

第一个空&#xff0c;用手工计算&#xff0c;可以用贪心法 先选择价值最大的物品&#xff0c;有两个价值是6的物品&#xff0c;重量合计246 剩余4个空间&#xff0c;只能放重量为2的物品&#xff0c;一共是66315 第二个空&#xff0c;需要将所有物品都放进背包舱室&#xff…

基于Python的量化交易回测框架Backtrader初识记录(一)

版权声明&#xff1a;本文为博主原创文章&#xff0c;如需转载请贴上原博文链接&#xff1a;基于Python的量化交易回测框架Backtrader初识记录&#xff08;一&#xff09;-CSDN博客 前言&#xff1a;近期以来&#xff0c;对股市数据获取及预处理算是告一段落&#xff0c;下一步…

OpenCV绘图函数(5)绘制标记函数drawMarker()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::drawMarker 函数在 OpenCV 中用于在一个给定的位置上绘制标记。目前支持几种不同的标记类型&#xff0c;具体信息可以参考 MarkerTypes 函数…

【C++ | 设计模式】观察者模式的详解与实现

1.概念 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为型设计模式&#xff0c;它的核心思想是定义对象间的一对多依赖关系&#xff0c;当一个对象的状态发生变化时&#xff0c;所有依赖于它的对象都会收到通知并自动更新。这个模式在现实生活中非常常见&#…

Selenium的四种部署方式详解

关于selenium 的部署&#xff0c;我在网上找了很多&#xff0c;基本上都没有提到或是说的比较清晰的。当时我一直有个困惑&#xff1a;测试的脚本代码&#xff0c;是放在跟浏览器同一台机器上呢&#xff0c;还是放在Application Server上&#xff1f; 在官方开发文档中&#x…

从0开始深度学习(2)——自动微分

1 微积分 1.1 导数和微分 略 1.2 偏导数 略 1.3 梯度&#xff08;gradient&#xff09; 1.3.1 定义 对于一个多变量函数 f ( x 1 , x 2 , … , x n ) f\left(x_{1}, x_{2}, \ldots, x_{n}\right) f(x1​,x2​,…,xn​)其中点 a ( a 1 , a 2 , … , a n ) \mathbf{a}(a_…

YGG深海传奇,创造财富无限可能!

随著区块链技术的创新与游戏产业的深度融合&#xff0c;GameFi赛道迅速崛起&#xff0c;成为全球投资者与玩家瞩目的新兴领域。 成立于2020年的Yield Guild Games(YGG)&#xff0c;作为全球区块链游戏领域的先锋公会之一&#xff0c;也加入到向去中心化经济模式的转型浪潮当中。…