全注解下的SpringIoc 续2-bean的生命周期

news2024/11/25 14:00:30

spring中bean的生命周期

上一个小节梳理了一下Spring Boot的依赖注入的基本知识,今天来梳理一下spring中bean的生命周期。
下面,让我们一起看看bean在IOC容器中是怎么被创建和销毁的。
bean的生命周期大致分为四个部分:

定义
初始化
生存期
销毁

bean的定义和初始化

大致流程如下:

Created with Raphaël 2.3.0 开始 资源定位(通过@ComponentScan注解定义的扫描规则去寻找被@Component、@Controller、@Service......等注解标记的类) 资源解析、并且将定义的信息保存起来 定义发布:将bean的定义信息发布到ioc容器中 bean的初始化 结束

默认情况下,spring会在启动时完成对bean的定义、发布以及初始化,但是,有时候我们并不想让spring在启动时就完成bean的初始化,更想的是在我们用到它时,才去完成初始化的动作,最常见的就是循环依赖的场景了。
而解决这个问题就需要用到spring的延迟初始化的机制了。

spring的延迟初始化bean机制

可以使用2中方法使bean进行延迟初始化:

@ComponentScan注解的lazyInit属性

@ComponentScan(basePackages = {"com.zzm.iocbeanlifeperiod"},lazyInit = true)

设置该属性为true后,对应的扫描规则下的bean都会进行延迟初始化

@Lazy注解

该注解用于指定某一个依赖的bean进行延迟初始化,用法如下:

	@Autowired
    @Lazy
    private Animal cat;

bean的初始化生命周期的各个阶段

好了,现在我们正式看看bean的生命周期的各个阶段,如下图所示:
在这里插入图片描述
这个流程介绍了bean从初始化到销毁的过程。
注意:流程中的setApplicationContext方法有些特殊,即使你定义了 ApplicationContextAware 接口,但是有时候并不会调用,这要根据你的 IoC器来决定。 我们知道, Spring IoC 容器最低的要求是实 BeanFactory 接口,而不是ApplicationContext 接口, 对于那些没有实现 Application Cont xt 接口的容器 ,在生命周期对应的 ApplicationContextAware 定义的方法也是不会被调用的,只有实现了 Applic ationContext 接口的容器,才会在生命周期调用 ApplicationContextAware 定义的 setApplicationContext
方法。

接下来,让我们一起测试一下bean的生命周期。
首先创建一个类,同时让它实现流程中的这些接口,代码如下:

@Component
@Slf4j
public class BeanLifePeriod implements BeanNameAware, BeanFactoryAware, ApplicationContextAware
        , InitializingBean, DisposableBean {
    
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        log.warn("【{}】调用了BeanFactoryAware的setBeanFactory",this.getClass().getSimpleName());
    }

    @Override
    public void setBeanName(String name) {
        log.warn("【{}】调用了BeanNameAware的setBeanName",this.getClass().getSimpleName());
    }

    @Override
    public void destroy() throws Exception {
        log.warn("【{}】调用了DisposableBean的destroy",this.getClass().getSimpleName());
    }

    @PreDestroy
    public void destroyMyself() {
        log.warn("【{}】调用了注解@PreDestroy定义的自定义销毁方法",this.getClass().getSimpleName());
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.warn("【{}】调用了InitializingBean的afterPropertiesSet",this.getClass().getSimpleName());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.warn("【{}】调用了ApplicationContextAware的setApplicationContext",this.getClass().getSimpleName());
    }

    @PostConstruct
    public void init(){
        log.warn("【{}】调用了注解@PostConstruct定义的自定义初始化方法",this.getClass().getSimpleName());
    }
}

因为BeanPostProcessor接口的方法是针对于所有的bean的,所以我们这里单独创建一个类来实现它:

@Component
@Slf4j
public class BeanPostProcessorExample implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        log.warn("BeanPostProcessor调用postProcessBeforeInitialization方法,参数【{},{}】"
                , bean.getClass().getSimpleName(), bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        log.warn("BeanPostProcessor调用postProcessAfterInitialization方法,参数【{},{}】"
                , bean.getClass().getSimpleName(), bean);
        return bean;
    }
}

接下来,创建ioc配置类和测试类

@ComponentScan(basePackages = {"com.zzm.iocbeanlifeperiod"})
@Configuration
@Slf4j
public class LifePeriodAppConfig {

}

public class IocBeanLifePeriod {

    public static void main(String[] args) throws InterruptedException {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LifePeriodAppConfig.class);
        context.close();
    }
}

运行main方法,可以看到如下日志:
在这里插入图片描述
上面的流程可用于自定义的bean,但是有时候bean不是我们自己定义的,而是第三方的bean,那怎么办呢?
在小节全注解下的IOC中我们介绍了@Bean注解,它可以用来向容器发布第三方的bean,所以通过它,我们也可以自定义初始化和销毁的方法,用法如下:

@ComponentScan(basePackages = {"com.zzm.iocbeanlifeperiod"})
@Configuration
@Slf4j
public class LifePeriodAppConfig {
    @Bean(value = "lifePeriodUser",initMethod = "init",destroyMethod = "destroy")
    public LifePeriodUser getUser(){
        return new LifePeriodUser().setId(3L).setUserName("Bean手动注入").setNote("Bean手动注入");
    }
}


@Data
@Accessors(chain = true)
@Slf4j
public class LifePeriodUser {
    private Long id;

    private String userName;

    private String note;

    public void init(){
        log.warn("【{}】调用了自定义用户初始化方法",this.getClass().getSimpleName());
    }

    public void destroy(){
        log.warn("【{}】调用了自定义用户销毁方法",this.getClass().getSimpleName());
    }
}

感兴趣的小伙伴可以自己尝试下,今天就到这里了。。。。。

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

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

相关文章

数据分类分级 数据识别-识别日期类型数据

前面针对数据安全-数据分类分级方案设计做了分析讲解,具体内容可点击数据安全-数据分类分级方案设计,不再做赘述 上面图片是AI创作生成!如需咒语可私戳哦! 目录 前言需求日期格式代码日期类型数据对应正则表达式前言 要做数据分类分级,重要的是分类分级模版的合理性和数…

一致性 Hash 算法 及Java TreeMap 实现

1、一致性 Hash 算法原理 一致性 Hash 算法通过构建环状的 Hash 空间替线性 Hash 空间的方法解决了这个问题,整个 Hash 空间被构建成一个首位相接的环。 其具体的构造过程为: 先构造一个长度为 2^32 的一致性 Hash 环计算每个缓存服务器的 Hash 值&…

「C/C++」C++对已有的类进行扩充

博客主页:何曾参静谧的博客 文章专栏:「C/C」C/C学习 目录 相关术语一、 继承二、组合 相关术语 继承:继承父类后可以拥有父类对应的属性和方法。 组合:将类作为成员对象,基类可以直接调用派生类对应的属性和方法。 一…

MySQL_第08章_聚合函数

第08章_聚合函数 讲师:尚硅谷 - 宋红康(江湖人称:康师傅) 官网: http://www.atguigu.com 我们上一章讲到了 SQL 单行函数。实际上 SQL 函数还有一类,叫做聚合(或聚集、分组)函…

59 openEuler 22.03-LTS 搭建MySQL数据库服务器-软件介绍和配置环境

文章目录 59 openEuler 22.03-LTS 搭建MySQL数据库服务器-软件介绍和配置环境59.1 软件介绍59.2 配置环境59.2.1 关闭防火墙并取消开机自启动59.2.2 修改SELINUX为disabled59.2.3 创建组和用户59.2.4 创建数据盘59.2.4.1 方法一:在root权限下使用fdisk进行磁盘管理5…

JVM笔记 —— 垃圾回收(GC)详解

一、垃圾回收的分类 针对HotSpot JVM的实现,它里面的GC其实准确分类只有两大种: Partial GC:部分收集模式 Young GC:只收集年轻代的GCOld GC:只收集老年代的GC。只有CMS中有这个模式。Mixed GC:收集整个年轻代以及部分…

mybatis的基本使用和理解

mybatis的基本使用和理解 Lombok的使用(使用注解的方式将实体类中的get、set、构造函数代替) Lombok是一个Java库,能自动插入编辑器并且构建工具,简化Java开发。通过添加注解的方式,不需要为类编写getter或equals方法&#xff0…

Vue3 + TS4.8踩坑之配置husky问题env: sh\r: No such file or directory

一、基本情况: 硬件环境:MacOS 10.14.6 背景:用vue3官方npm init vuelatest初始化创建的vue3 ts4.8项目。 二、问题和解决方案: 问题1:git commit的时候提示:env: sh\r: No such file or directory 原…

0121 进程管理

1.在Linux中,每个执行的程序都称为一个进程。每一个进程都分配一个ID号(pid进程号) 2.每个进程都可能以两种方式存在,前台和后台。前台进程即用户当前屏幕上可进行的操作,后台进程即实际操作,由于屏幕上无…

Java中源文件声明规则,以及java包,import关键字的使用

Java中源文件声明规则,以及java包,import关键字的使用。 1. 源文件声明规则 当在一个源文件中定义多个类,并且还有import语句和package语句时,要特别注意以下规则: a. 一个源文件中只能有一个 public 类。 b. 一个源…

LC电路是如何产生振荡的

电容和电感是两个储能元件,当电源给电容充电完成后, 将开关切到电感,电电感两端的电压是一个正弦波,正弦波频率是: 这时我们称电感和电容产生了振荡。 当然由于电感和电容都是有损耗的,所以这种振荡会慢慢的衰减&…

【文献查找使用】

目录 知识框架No.1 中文文献一、查找、二、下载、三、引用、页码四、什么是DOI呢??? No.2 外文文献一、查找二、下载三、引用、页码 No.3 如何在不下载的情况下进行正确引用呢??一、谷歌学术进行查询二、上sci-hub网站…

使用python的cartopy库读取shapefile文件 .shp文件是乱码

文章目录 问题解决方法 问题 使用python的cartopy库读取shapefile文件即.shp文件乱码 我在使用python的cartopy库读取shapefile文件时出现了乱码 record的.attributes的[‘name’]都是乱码 from cartopy.io import shapereader shp_pathr/home/mw/project/北京市1.shp#文件路…

【Linux 裸机篇(六)】I.MX6U 主频和时钟配置

目录 一、时钟系统详解1. 系统时钟来源2. 7路 PLL 时钟源2.1 ARM_PLL (PLL1)2.2 528_PLL (PLL2)2.3 USB1_PLL (PLL3)2.4 USB2_PLL (PLL7)2.5 ENET_PLL (PLL6)2.6 VIDEO_PLL (PLL5)2.7 AUDIO_PLL (PLL4) 3. 时钟树简介4. 内核时钟设置5. PFD 时钟设置6. AHB、 IPG 和 PERCLK 根时…

SQLite数据库简单小入门学习(一)

目录 一、认识数据库(一)数据库简介(二)数据库类型 二、SQLite数据库(一)SQLite简介(二)学习所需工具(1)scott.db(2)SQLiteSpy.exe &a…

【分布式理论】聊一下 ACID、BASE、CAP、FLP

分布式理论基础 今天我们来聊一下分布式相关基础理论基础,上一篇文章中,我描述了一下分布式系统的纲,但是想要入手学习分布式系统设计,其实需要先从基本理论开始。而知名的ACID、BASE、CAP、FLP都是相关的理论基础。 ACID ACID…

STM32平衡小车 TB6612电机驱动学习

TB6612FNG简介 单片机引脚的电流一般只有几十个毫安,无法驱动电机,因此一般是通过单片机控制电机驱动芯片进而控制电机。TB6612是比较常用的电机驱动芯片之一。 TB6612FNG可以同时控制两个电机,工作电流1.2A,最大电流3.2A。 VM电…

C++ [STL-简介]

本文已收录至《C语言和高级数据结构》专栏! 作者:ARMCSKGT ​​​​​​​​ 文章目录 前言正文简介关于STL各种版本 STL组件容器迭代器配接器(适配器)算法仿函数空间配置器 STL的重要性学习STL的意义如何学习STL STL的缺陷 最后 前言 STL(standard tem…

Django+Vue的一个用户数据分析展示

文章目录 Git地址、项目所需文件总体效果展示一、项目环境所需二、Django代码解析2.1、执行文件2.2、注册app01 Git地址、项目所需文件 SQL数据文件和用户需求文件 提取码 1111 Git克隆地址 zip下载 其中第一个连接是数据文件,后两个连接选一个即可 总体效果展示 …

从idea向GitLab上传代码图文详解

这里写目录标题 一 新建一个idea工程二 点击左下角Version Control三 上传到GitLab四 给IDEA发链接五 回gitlab上校验六 去gitlab上把代码拖回来 在安装完gitlab插件,辛苦的配置完gitlab环境后,向gitlab中提交代码变成了首要任务 一 新建一个idea工程 二…