Spring Bean 生命周期详解

news2024/11/27 0:23:07

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

在这里插入图片描述

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

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

相关文章

Avue-data数据大屏显示饼图(附Demo)

目录 前言1. Sql查询2. 颜色细节 前言 对于这部分知识,原先有过柱状图实战:Avue-data数据大屏显示柱状图(附Demo讲解) 以下直奔主题,以Sql数据库数据为主 1. Sql查询 以饼图为例,需要返回的形式如下&am…

在敏捷项目管理中实施 Scrum 方法

在本文中,我将阐明敏捷项目管理中的 Scrum 流程。我将深入探讨 Scrum 方法论中不可或缺的角色。本文将全面概述敏捷开发中的 Scrum 流程。我将解释 Scrum 的核心组件,详细探索端到端 Scrum 流程。在本文结束时,您将清楚地了解 Scrum 的工作原…

Ant Design Vue Cascader 级联选择 错位问题

当Cascader 多个的时候 对应的下列会错位 如果滚动 他不会跟着元素 而是会跟着屏幕滚动&#xff0c;如下效果 解决方法 在Cascader 标题添加 getPopupContainer 属性监听对应的位置&#xff0c;返回对应的元素 <a-cascader class"smart-width-100 " v-model:…

QThread 与QObject::moveToThread在UI中的应用

1. QThread的两种用法 第一种用法就是继承QThread&#xff0c;然后覆写 virtual void run()&#xff0c; 这种用法的缺点是不能利用信号槽机制。 第二种用法就是创建一个线程&#xff0c;创建一个对象&#xff0c;再将对象moveToThread, 这种可以充分利用信号槽机制&#xff…

Android-Android Studio-FAQ

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

华为DCN技术:M-LAG

M-LAG&#xff08;Multichassis Link Aggregation Group&#xff09;即跨设备链路聚合组&#xff0c;是一种实现跨设备链路聚合的机制。M-LAG主要应用于普通以太网络、VXLAN和IP网络的双归接入&#xff0c;可以起到负载分担或备份保护的作用。相较于另一种常见的可靠性接入技术…

vue实现的商品列表网页

一、商品列表效果如下 二、代码&#xff1b; vue实现的商品列表网页 &#xff0c; 图片在vue项目的Public文件夹里的 imgs中 <template><div class"common-layout"><!-- el-container:外层容器。 当子元素中包含 <el-header> 或 <el-foo…

每天写java到期末考试(6.22)--集合5--练习

集合方法 正常输入对象到集合里面&#xff0c;运用public使用类方法 import java.util.ArrayList;public class test {public static void main(String[] args) {ArrayList<Student> listnew ArrayList<>();//2.创建学生对象Student s1new Student("yanxiao1&…

Allegro X PCB设计小诀窍系列--如何在Allegro X中将动态铜皮冻结

背景介绍&#xff1a;我们在进行PCB设计时&#xff0c;经常会用到动态铜皮&#xff0c;因为动态铜皮可以根据约束规则设置进行自动调整。但是在一些设计场景中&#xff0c;设计人员不希望对印制板的调整影响到动态铜皮&#xff0c;如果将动态铜皮转换为静态铜皮&#xff0c;又可…

Apple - Core Foundation Design Concepts

本文翻译整理自&#xff1a;Core Foundation Design Concepts&#xff08;更新日期&#xff1a;2013-12-16 https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFDesignConcepts/CFDesignConcepts.html#//apple_ref/doc/uid/10000122i 文章…

reidis的内存回收和内存淘汰策略

redis的内存回收 8种内存淘汰策略

地缘风险对出口的影响分析

核心观点 5月以来&#xff0c;CCFI运价涨幅显著扩大。除外需回暖外&#xff0c;集运“涨价”还有哪些催化因素&#xff0c;或如何影响后续出口&#xff1f; 一问&#xff1a;装箱航线运价大幅上涨背后&#xff1f;5月以来运价明显上涨&#xff0c;与外需复苏、出口改善相互印证…

基于uni-app和图鸟UI的云课堂小程序开发实践

摘要&#xff1a; 随着移动互联网的快速发展&#xff0c;移动学习已成为教育领域的重要趋势。本文介绍了基于uni-app和图鸟UI框架开发的云课堂小程序&#xff0c;该小程序实现了移动教学、移动学习、移动阅读和移动社交的完美结合&#xff0c;为用户提供了一个便捷、高效的学习…

数仓中数据分层的标准流向解读

在大数据开发中&#xff0c;数据分层是一个至关重要的概念。合理的数据分层可以有效地提升数据处理的效率和质量。本文将详细介绍数据分层的标准流向和相关注意事项&#xff0c;并结合实际应用进行说明。 数据分层的标准流向 根据行业标准&#xff0c;数据分层的标准流向如下…

七、yolov8图像标注和模型训练(目标检测)

环境配置方法&#xff1a;点这里 环境配置完毕后&#xff0c;需要进行标注工作和训练任务&#xff0c;以下分两个部分进行。 图片标注 1、按照以下的格式&#xff0c;将图片放入images中。&#xff08;不限制文件夹路径&#xff09; 2、然后下载labelme标注工具&#xff0…

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

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

百度地图3d区域掩膜,最常见通用的大屏地图展现形式

需求及效果 原本项目使用的是百度地图3.0,也就是2d版本的那个地图,客户不满意觉得不够好看,让把地图改成3d的,但是我们因为另外的系统用的都是百度地图,为了保持统一只能用百度地图做 经过3天的努力,最后我终于把这个效果实现了,效果如下: 如何引用GL版本 为了实现…

DDK电通拧紧MFC-S060控制器过流维修

一、DDK伺服拧紧轴控制器过流故障的成因 1. 电源电压过低&#xff1a;当电源电压过低时&#xff0c;控制器可能会出现过流现象。 2. 负载过大&#xff1a;当负载过大时&#xff0c;DDK电通拧紧机控制器MFC-S060的电流也会随之增大&#xff0c;可能导致过流故障。 3. 控制器内部…

Java——IO流(一)-(6/8):字节流-FileInputStream 每次读取多个字节(示例演示)、一次读取完全部字节(方式一、方式二,注意事项)

目录 文件字节输入流&#xff1a;每次读取多个字节 实例演示 注意事项 文件字节输入流&#xff1a;一次读取完全部字节 方式一 方式二 注意事项 文件字节输入流&#xff1a;每次读取多个字节 用到之前介绍过的常用方法&#xff1a; 实例演示 需求&#xff1a;用每次读取…

Linux测试服务器端口是否打开

前言 服务器端口在计算机网络通信中扮演着至关重要的角色&#xff0c;其作用可以归纳如下&#xff1a; 区分不同的应用程序或服务&#xff1a; 服务器端口用于标识和定位不同应用程序或服务在服务器上的通信入口。 通过不同的端口号&#xff0c;服务器可以同时运行多个应用程…