Bean 的生命周期总结

news2024/11/28 10:32:11

 

目录

一、Bean生命周期的五个阶段

Bean的初始化

二、@PostConstruct 和 @PreDestroy 各自的效果

三、 实例化和初始化的区别

四、为什么要先设置属性在进⾏初始化呢?

一、Bean生命周期的五个阶段

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

Bean作为一个Java对象,具有一定的生命周期。它的生命周期包括以下几个阶段:

  1. 实例化:在Java应用程序中,Bean对象是通过new关键字或者反射机制来实例化的。在这个阶段,Bean对象被创建,并分配了内存空间。
  2. 设置属性(Bean注入和装配)
  3. 初始化:当Bean对象被创建后,需要进行初始化,包括设置属性值、执行一些初始化操作等。在Spring框架中,Bean的初始化可以通过配置文件中的init-method属性进行指定。
  4. 使用:在Bean初始化之后,它就可以被应用程序使用了。在使用过程中,Bean可能会调用其他对象的方法,从而导致其他Bean对象被实例化和初始化。
  5. 销毁:当Bean对象不再被使用时,应该将其销毁并释放占用的内存空间。在Spring框架中,Bean的销毁可以通过配置文件中的destroy-method属性进行指定。

总的来说,Bean对象的生命周期可以通过实例化、初始化、使用和销毁这几个阶段来描述。在Spring框架中,Bean的生命周期还可以通过BeanPostProcessor接口来进行扩展和定制。

为了便于理解  我们引用一个现实中的事件来形容  

Bean 的⽣命流程看似繁琐,但咱们可以以⽣活中的场景来理解它,⽐如我们现在需要买⼀栋房⼦,那么我们的流程是这样的:
1. 先买房(实例化,从⽆到有);
2. 装修(设置属性);
3. 买家电,如洗⾐机、冰箱、电视、空调等([各种]初始化);
4. ⼊住(使⽤ Bean);
5. 卖出去(Bean 销毁)。 

Bean的初始化

  1. 执行各种通知(BeanNameAware、BeanFactoryAware)等接口方法
  2. 初始化的前置方法(PostConstruct)
  3. 初始化方法
  4. 初始化的后置方法(PreDestroy)

下面用代码演示整个Bean的生命周期:
我们用构造方式来展示实例化的效果 ,实例化和属性设置是 Java 级别的系统“事件”,其操作过程不可⼈⼯⼲预和修改  所以下面没有演示设置属性

package com.example.bean.test;

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 {

    private String name;

    public BeanLifeComponent() {
        System.out.println("实例化方法执行拉");
    }


    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("销毁方法执行");
    }
}

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

package com.example.bean.test;

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;
    }
}

 在得到上下文对象这里  因为我们是使用springboot演示的 所以我们使用ConfigurableApplicationContext 来得到上下文对象

package com.example.bean.test;

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();
    }
}

结果如下: 

二、@PostConstruct 和 @PreDestroy 各自的效果

  1. 当Bean被容器初始化之后,会调用@PostConstruct的注解方法。
  2. 当Bean在容器销毁之前,调用被@PreDestroy注解的方法

代码如下:所以,PostConstruct 注释用于在依赖关系注入完成之后需要执行的方法上,以执行任何初始化。此方法必须在将类放入服务之前调用。支持依赖关系注入的所有类都必须支持此注释。即使类没有请求注入任何资源,用PostConstruct 注释的方法也必须被调用。只有一个方法可以用此注释进行注释。

    @PostConstruct
    public void doPostConstruct(){
        System.out.println("执行了 新版本@PostConstruct 前置初始化方法");
    }
    @PreDestroy
    public void doPreDestroy(){
        System.out.println("执行新版本 @PreDestroy 销毁方法");

    }

PreDestroy 用与在依赖注入完成之前的方法前面执行,遵守准则:

  1. 该方法不得有任何参数
  2. 该方法的返回类型必须为 void;
  3. 该方法不得抛出已检查异常;
  4. 应用 PostConstruct 的方法可以是 public、protected、package private 或 private;
  5. 该方法不能是 static;该方法可以是 final;
  6. 该方法只会被执行一次

三、 实例化和初始化的区别

实例化和属性设置是 Java 级别的系统“事件”,其操作过程不可⼈⼯⼲预和修改;⽽初始化是给开发者提供的,可以在实例化之后,类加载完成之前进⾏⾃定义“事件”处理。

四、为什么要先设置属性在进⾏初始化呢?

仔细观察下面代码:

    @Service
    public class UserService {
        public UserService(){
            System.out.println("调⽤ User Service 构造⽅法");
        }
        public void sayHi(){
            System.out.println("User Service SayHi.");
        }
    } 
    @Controller
    public class UserController {
        @Resource
        private UserService userService;
        @PostConstruct
        public void postConstruct() {
            userService.sayHi();
            System.out.println("执⾏ User Controller 构造⽅法");
        }
    }

我们可以发现很是为了避免空指针异常。

 

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

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

相关文章

深度学习的数值问题

文章目录 梯度下降临界点、驻点、拐点、鞍点、顶点(曲线)、曲率近似优化预测最佳步长 梯度下降 往斜率的反方向走。 临界点、驻点、拐点、鞍点、顶点(曲线)、曲率 临界点:在数学中,临界点是指函数的导数为…

【APISIX】W10安装APISIX

Apache APISIX 是一个动态、实时、高性能的云原生 API 网关,提供了负载均衡、动态上游、灰度发布、服务熔断、身份认证、可观测性等丰富的流量管理功能。以下简单介绍Windows下借助Docker Desktop来安装APISIX。 具体应用场景可参考官网(https://apisix.…

安科瑞铁塔基站能耗监控解决方案

安科瑞 华楠 1 背景概述 5G发展,基站先行。5G基站的选址建设,是保证5G信号覆盖的基础,因此5G基站建设是5G产业布局的一部分,也是5G成熟的基础。 2G、3G、4G均是低频段信号传输,宏基站几乎能应付所有的信号覆盖。但由…

Navicat Premium 16 安装及卸载

Navicat Premium 16 安装及卸载 文章目录 Navicat Premium 16 安装及卸载一 、简介二、下载三、安装四、使用五、卸载 一 、简介 Navicat Premium 是一套可创建多个连接的数据库开发工具,让你从单一应用程序中同时连接 MySQL、Redis、MariaDB、MongoDB、SQL Server、…

【HTML专栏4】常用标签(标题、段落、换行、文本格式化、注释及特殊字符)

本文属于HTML/CSS专栏文章,适合WEB前端开发入门学习,详细介绍HTML/CSS如果使用,如果对你有所帮助请一键三连支持,对博主系列文章感兴趣点击下方专栏了解详细。 博客主页:Duck Bro 博客主页系列专栏:HTML/CS…

线程的常用方法及六种状态

一、线程核心执行流程方法 -- run() run方法是Runnable接口中定义的。所有实现Runnable的接口的子类都需要覆写run方法。 run方法是线程的核心执行流程方法,也就是说,run方法决定了线程启动后要干什么,当run方法执行完…

2.11 PE结构:添加新的节区

在可执行PE文件中,节(section)是文件的组成部分之一,用于存储特定类型的数据。每个节都具有特定的作用和属性,通常来说一个正常的程序在被编译器创建后会生成一些固定的节,通过将数据组织在不同的节中&…

微信小程序接入隐私弹窗说明及详细过程

相信各位做小程序的小伙伴在微信小程序后台应该都接到了官方通知的小程序隐私新规,如果还未收到的小程序可以看一下: 为规范开发者的用户个人信息处理行为,保障用户合法权益,自2023年9月15日起,对于涉及处理用户个人信…

OpenCV 09(形态学)

一、形态学 形态学指一系列处理图像 形状特征 的图像处理技术. 形态学的基本思想是利用一种特殊的结构元(本质上就是卷积核)来测量或提取输入图像中相应的形状或特征,以便进一步进行图像分析和目标识别。这些处理方法基本是对二进制图像进行处理, 即黑白图像卷积核…

JUC编程中锁引发的“见解”

JUC编程中锁引发的“见解” 一大早就在想锁是干嘛的?什么情况下要用锁?想了很多,下面的所有表述都是就是我的思考流程,欢迎所有人一起讨论、更正。 文章目录 JUC编程中锁引发的“见解”1、什么是JUC编程?2、JUC编程中什么情况下需…

C/C++之链表的建立

个人主页:点我进入主页 专栏分类:C语言初阶 C语言程序设计————KTV C语言小游戏 C语言进阶 C语言刷题 欢迎大家点赞,评论,收藏。 一起努力,一起奔赴大厂。 目录 1.头插 1.1简介 1.2代码实现头插 …

二维数组前缀和(JAVA)

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 暴力 双层for循环,遍历子矩阵。 前缀和算法: class NumMatrix {private int sum[][];private int matrix[][];public NumMatrix(int[][] matrix) {this.matrixmatrix;int row…

AI 帮我写代码——Amazon CodeWhisperer 初体验

文章作者:游凯超 人工智能的突破和变革正在深刻地改变我们的生活。从智能手机到自动驾驶汽车,AI 的应用已经深入到我们生活的方方面面。而在编程领域,AI 的崭新尝试正在开启一场革命。Amazon CodeWhisperer,作为亚马逊云科技的一款…

【高德地图】 覆盖物/画点/画折线/画多边形/画矩形/画圆

官方示例 https://lbs.amap.com/demo/javascript-api/example/mouse-operate-map/mouse-draw-overlayers <!doctype html> <html lang"en"><head><meta charset"utf-8"><meta http-equiv"X-UA-Compatible" content…

07_瑞萨GUI(LVGL)移植实战教程之LVGL对接EC11旋转编码器驱动

本系列教程配套出有视频教程&#xff0c;观看地址&#xff1a;https://www.bilibili.com/video/BV1gV4y1e7Sg 7. LVGL对接EC11旋转编码器驱动 本次实验我们向LVGL库中对接EC11旋转编码器驱动&#xff0c;让我们能通过EC11旋转编码器操作UI。 7.1 复制工程 上次实验得出的工…

一文读懂Swin-Transformer

系列文章目录 记录CV领域大模型的学习历程&#xff0c;欢迎大家一起讨论&#xff0c;互相学习。 ViT,DETR(一),DETR(二)DETR(三) 文章目录 系列文章目录前言一、整体框架1.Patch Embedding2.Patch Merging3.Swin Transformer Block3.1 Window Partition/Reverse3.2 Window-MSA…

C#__文件操作之FileInfo和DirectoryInfo

// 代码&#xff08;含注释&#xff09; class Program{static void Main(string[] args){// FileInfo 文件操作FileInfo myFile new FileInfo("D:\C#编程\文件操作之FileInfo和DirectoryInfo\TextFile1.txt");// 实例方法// myFile.CopyTo("D:\C#编程\文件操作…

空中跳一跳

欢迎来到程序小院 空中跳一跳 玩法&#xff1a; 跳一跳长按鼠标左键&#xff0c;松开鼠标进行跳跃&#xff0c;跳到下一个格子中&#xff0c;进行分数统计&#xff0c;三次生命机会&#xff0c;格子中也会有爱心出现&#xff0c;吃掉安心增加一次生命哦^^。开始游戏https://ww…

第19章 并发与竞争实验(iTOP-RK3568开发板驱动开发指南 )

在前面章节的学习中&#xff0c;相信大家已经对用户空间与内核空间数据传递进行了实验&#xff0c;假如要传递的数据被存放在了全局变量&#xff0c;该数据就可以作为共享资源被多个任务共同读写&#xff0c;从而造成数据的错误传输&#xff0c;多个程序同时访问一个共享资源产…

取个好名,是一生中极为重要之事

我们每十年一大运&#xff0c;五年一小运。每交次大运时&#xff0c;就会改变一次你身边的一切环境。每个大运&#xff0c;都会把你带入不同的风景&#xff0c;人生想要须尽欢&#xff0c;就不要太在意外在的一切&#xff0c;永远向内求。有志同道合的人就一起上路&#xff0c;…