Spring Bean 生命周期详解

Spring Bean 生命周期详解

在 Spring 框架中,Bean 的生命周期由 Spring 容器全权管理。了解和掌握 Bean 的生命周期对于使用 Spring 开发稳定且高效的应用程序至关重要。本文将详细介绍 Spring Bean 生命周期的五个主要阶段:实例化、属性注入、初始化、使用和销毁,并涵盖各个阶段的关键步骤和扩展点。

1. 实例化(Instantiation)

实例化阶段包括以下关键步骤:

  • BeanNameAware 接口:如果 Bean 实现了 BeanNameAware 接口,Spring 将调用其 setBeanName 方法,将 Bean 的名称传递给它。
  • BeanFactoryAware 接口:如果 Bean 实现了 BeanFactoryAware 接口,Spring 将调用其 setBeanFactory 方法,将 BeanFactory 实例传递给它。

这些步骤确保 Bean 具有必要的上下文信息,可以与 Spring 容器进行交互。

@Override
public void setBeanName(String beanName) {
    System.out.println("BeanNameAware: setBeanName called with name " + beanName);
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    System.out.println("BeanFactoryAware: setBeanFactory called");
}

2. 属性注入(Property Injection)

在实例化之后,Spring 容器会根据配置文件或注解,将配置的属性值或依赖对象注入到 Bean 实例中。这一阶段包括以下关键步骤:

  • 属性设置:Spring 容器根据配置文件或注解,将配置的属性值注入到 Bean 实例中。
  • 依赖注入:Spring 容器根据配置文件或注解,将依赖对象注入到 Bean 实例中。
public class MyBean {

    private String name;

    public void setName(String name) {
        this.name = name;
    }
}

3. 初始化(Initialization)

初始化阶段是 Bean 生命周期中最复杂的阶段,它包括属性设置、依赖注入和初始化方法的调用。该阶段包括以下关键步骤:

  • BeanPostProcessor 的 postProcessBeforeInitialization 方法:Spring 调用所有注册的 BeanPostProcessor 实现的 postProcessBeforeInitialization 方法,以便在 Bean 初始化前对其进行处理。
  • InitializingBean 接口和自定义初始化方法:如果 Bean 实现了 InitializingBean 接口,Spring 将调用其 afterPropertiesSet 方法。此外,如果配置了自定义的初始化方法,Spring 也会调用该方法。
  • @PostConstruct 注解:如果 Bean 的某个方法使用了 @PostConstruct 注解,Spring 容器将在依赖注入完成后调用该方法。@PostConstruct 注解用于标注在依赖注入完成后需要执行的初始化方法,比实现 InitializingBean 接口更加灵活和通用。
  • BeanPostProcessor 的 postProcessAfterInitialization 方法:Spring 调用所有注册的 BeanPostProcessor 实现的 postProcessAfterInitialization 方法,以便在 Bean 初始化后对其进行处理。
import javax.annotation.PostConstruct;

public class MyBean {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @PostConstruct
    public void init() {
        System.out.println("PostConstruct: init method called");
        this.name = "Initialized Bean";
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean: afterPropertiesSet called");
    }

    public void customInit() {
        System.out.println("Custom init-method: customInit called");
    }
}

4. 使用(Ready to Use)

在完成初始化后,Bean 进入使用阶段。在这个阶段,Bean 处于完全初始化状态,可以被应用程序使用。这个阶段没有特定的扩展点,但这是应用程序逻辑使用和操作 Bean 的主要时间段。

public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    MyBean myBean = context.getBean(MyBean.class);
    System.out.println("Using MyBean: " + myBean);
    context.close();
}

5. 销毁(Destruction)

当 Spring 容器关闭时,Bean 进入销毁阶段。这个阶段包括以下关键步骤:

  • DisposableBean 接口和自定义销毁方法:如果 Bean 实现了 DisposableBean 接口,Spring 将调用其 destroy 方法。此外,如果配置了自定义的销毁方法,Spring 也会调用该方法。

这些步骤确保在销毁 Bean 之前执行必要的清理操作,释放资源。

@Override
public void destroy() throws Exception {
    System.out.println("DisposableBean: destroy called");
}

public void customDestroy() {
    System.out.println("Custom destroy-method: customDestroy called");
}

完整示例

为了更好地理解这些阶段,我们提供一个完整的示例,包括 Bean 类、BeanPostProcessor 和 Spring 配置。

Bean 类

package com.example.lifecycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.DisposableBean;

public class MyBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void setBeanName(String beanName) {
        System.out.println("BeanNameAware: setBeanName called with name " + beanName);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("BeanFactoryAware: setBeanFactory called");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("ApplicationContextAware: setApplicationContext called");
    }

    @PostConstruct
    public void init() {
        System.out.println("PostConstruct: init method called");
        this.name = "Initialized Bean";
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean: afterPropertiesSet called");
    }

    public void customInit() {
        System.out.println("Custom init-method: customInit called");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean: destroy called");
    }

    public void customDestroy() {
        System.out.println("Custom destroy-method: customDestroy called");
    }
}

BeanPostProcessor

package com.example.lifecycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class CustomBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor: postProcessBeforeInitialization called for " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor: postProcessAfterInitialization called for " + beanName);
        return bean;
    }
}

Spring 配置

package com.example.lifecycle;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean(initMethod = "customInit", destroyMethod = "customDestroy")
    public MyBean myBean() {
        MyBean myBean = new MyBean();
        myBean.setName("Test Bean");
        return myBean;
    }

    @Bean
    public CustomBeanPostProcessor customBeanPostProcessor() {
        return new CustomBeanPostProcessor();
    }
}

测试 Spring 配置

package com.example.lifecycle;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class SpringLifecycleDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        
        MyBean myBean = context.getBean(MyBean.class);
        System.out.println("Using MyBean: " + myBean);

        context.close();
    }
}

参考链接

  1. Spring Framework Documentation
  2. TutorialsPoint: Spring Bean Life Cycle

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何基于Redis实现分布式锁?

分布式锁介绍 对于单机多线程来说,在 Java 中,我们通常使用 ReetrantLock 类、synchronized 关键字这类 JDK 自带的 本地锁 来控制一个 JVM 进程内的多个线程对本地共享资源的访问。 下面是我对本地锁画的一张示意图。 本地锁 从图中可以看出&#xf…

NetSuite Non-Inventory Item 公司内外采购总账影响

上篇文章提到,Non-Inventory Item的科目维护会根据各个企业的实际情况而有所不同,通常情况下都涉及外部交易,即对外采购与销售;另外也涉及到公司内部的相关交易,本篇以采购为例,来看看公司内外采购交易所对…

【分布式系列】分布式锁timeout了怎么办?

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Apache IoTDB vs InfluxDB 开源版,架构性能全面对比!

分布式、端边云同步、读写查询性能,Apache IoTDB 与 InfluxDB 开源版的详尽对照! 在物联网(IoT)领域,数据的采集、存储和分析是确保系统高效运行和决策准确的重要环节。随着物联网设备数量的增加和数据量的爆炸式增长&…

Mysql安装 /lib64/libc.so.6: version `GLIBC_2.28‘ not found 缺少 glibc-2.28.tar.gz

问题:安装Mysql出现 Error mysql/bin/mysqld: /lib64/libm.so.6: version GLIBC_2.27 not found (required by mysql/bin/mysqld) mysql/bin/mysqld: /lib64/libc.so.6: version GLIBC_2.28 not found (required by mysql/bin/mysqld) mysql/bin/mysqld: /lib64/lib…

【仿真建模-anylogic】INetwork相关接口说明

Author:赵志乾 Date:2024-06-22 Declaration:All Right Reserved!!! 1. 类图 2. 说明 INetwork为辊道网络、路线网路的顶层接口,其组成元素有节点和路径两种,对应的接口为INode、IP…

Android-Android Studio-FAQ

1 需求 2 接口 3 Android Studio xml布局代码补全功能失效问题 最终解决方案就是尝试修改compileSdk 为不同SDK版本来解决问题,将原本34修改为32测试会发现xml代码补全功能有效了! 参考资料 Android Studio xml布局代码补全功能失效问题_android studi…

10.华为路由器使用ospf动态路由连通两个部门网络

目的:实验ospf动态路由协议连通A与B部门 AR1配置 [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 1.1.1.1 24 [Huawei]vlan batch 10 [Huawei]int Vlanif 10 [Huawei]int e0/0/0 [Huawei-Ethernet0/0/0]port link-type access [Huawei-Ethernet0/0/0]por…

CubeFS - 新一代云原生存储系统

CubeFS 是一种新一代云原生存储系统,支持 S3、HDFS 和 POSIX 等访问协议,支持多副本与纠删码两种存储引擎,为用户提供多租户、 多 AZ 部署以及跨区域复制等多种特性。 官方文档 CubeFS 作为一个云原生的分布式存储平台,提供了多种访问协议,因此其应用场景也非常广泛,下面…

Apple - Text Attribute Programming Topics

本文翻译整理自:Text Attribute Programming Topics(更新日期:2004-02-16 https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TextAttributes/TextAttributes.html#//apple_ref/doc/uid/10000088i 文章目录 一、文…

音视频开发—FFmpeg 打开摄像头进行RTMP推流

实验平台:Ubuntu20.04 摄像头:普通USB摄像头,输出格式为YUV422 1.配置RTMP服务器推流平台 使用Nginx 配置1935端口即可,贴上教程地址 ubuntu20.04搭建Nginxrtmp服务器) 2.配置FFmpeg开发环境 过程较为简单,这里不…

【龙晰 离线安装openssl-devel】openssl-devel rpm 离线安装 需要下载哪些安rpm 包

进入龙晰镜像源地址下载 http://mirrors.openanolis.cn/anolis/8/BaseOS/x86_64/os/Packages/(base) [rootAI lib64]# yum install openssl-devel Last metadata expiration check: 14:03:32 ago on Fri 21 Jun 2024 07:26:56 AM CST. Dependencies resolved. Package …

不服 GPT-4o ,就是干?

OpenAI 最大的对手 Anthropic ,深夜发布了他们迄今为止最智能的模型:Claude 3.5 Sonnet。 这俩家公司的竞争愈演愈烈,Anthropic 声称新 Claude AI 超越了 GPT-4o。 通过 Anthropic 发布的测试报告来看,新模型在推理、知识储备、代…

怎么处理整合了shiro的应用的RPC接口鉴权问题

这篇文章分享一下:当一个服务提供者整合了shiro安全框架来实现权限访问控制时,服务消费者通过feign请求服务提供者的接口时的鉴权不通过问题。 问题描述 博主有一个项目pms(权限管理系统),使用了shiro框架来实现鉴权功…

什么是局域网IP?

局域网IP(Local Area Network IP)指的是在局域网内使用的IP地址。局域网是指在某个地理区域内,由一组相互连接的计算机组成的小型网络,常见于家庭、学校、办公室等场所。局域网IP可以用来实现内网穿透,即在复杂的网络环…

http发展史(http0.9、http1.0、http1.1、http/2、http/3)详解

文章目录 HTTP/0.9HTTP/1.0HTTP/1.1队头阻塞(Head-of-Line Blocking)1. TCP 层的队头阻塞2. HTTP/1.1 的队头阻塞 HTTP/2HTTP/3 HTTP/0.9 发布时间:1991年 特点: 只支持 GET 方法没有 HTTP 头部响应中只有 HTML 内容&#xff0…

2.XSS-存储型

储存型XSS 或持久型 XSS 交互的数据会被存在在数据库里面,永久性存储,具有很强的稳定性。 在留言板里面进行测试一下是否有做过滤 "<>?&66666点击提交 查看元素代码&#xff0c;已经提交完成&#xff0c;并且没有做任何的过滤措施 接下来写一个javascrip…

2024年十大数据集成工具和软件应用场景解析

详细阐述了十大数据集成工具及其优缺点&#xff1a; 数据集成的挑战 在当今的商业环境中&#xff0c;企业常常面临着数据分散、系统孤立的难题。传统的数据集成方式&#xff0c;就像一张复杂的蜘蛛网&#xff0c;难以理顺&#xff0c;令人头痛不已。 数据孤岛: 各个业务系统独立…

使用Jetpack Compose为Android App创建自定义页面指示器

使用Jetpack Compose为Android App创建自定义页面指示器 在现代移动应用中&#xff0c;页面指示器在提供视觉导航提示方面发挥着重要作用&#xff0c;帮助用户理解其在应用内容中的当前位置。页面指示器特别适用于顺序展示内容的场景&#xff0c;如图片轮播、图像库、幻灯片放…

在自托管基础设施上使用 GitOps 部署 MinIO

基于MinIO Weaviate Python GitOps探索的见解&#xff0c;本文探讨了如何增强软件部署流程的自动化。 通过将 GitHub Actions 与 Docker Swarm 集成而产生的协同作用&#xff0c;以自托管基础架构的稳健性为基础&#xff0c;标志着 CI/CD 实践的关键进步。这种方法不仅利用了软…