Spring中Bean的生命周期详解

目录

  1. Bean的定义和作用
  2. Bean的生命周期概述
  3. Bean实例化阶段
  4. 依赖注入阶段
  5. 初始化阶段
  6. Bean的使用
  7. 销毁阶段
  8. 完整的Bean生命周期流程
  9. 示例代码
  10. 总结

Bean的定义和作用

在Spring框架中,Bean是指由Spring IoC容器管理的Java对象。Bean是构建Spring应用程序的基本单元,几乎所有的Java对象都可以被定义为Bean来交由容器管理。Bean的主要作用包括以下几点:

  1. 解耦合:通过依赖注入(Dependency Injection,DI),使得对象之间的依赖关系不再直接管理,减少代码耦合。
  2. 生命周期管理:Spring容器负责管理Bean的创建、初始化、使用和销毁等全过程。
  3. 配置简化:通过配置文件(如XML或注解)来管理对象的创建和依赖关系,减少硬编码。
  4. 统一管理:容器统一管理Bean的实例数量和作用范围(Scope),节省资源。

Bean的生命周期概述

Bean的生命周期可以分为以下几个主要阶段:

  1. 实例化阶段:通过构造函数或工厂方法创建Bean实例。
  2. 依赖注入阶段:将所需的依赖注入到Bean中。
  3. 自定义初始化阶段:执行自定义的初始化方法来进行额外的Bean设置。
  4. Bean的使用:Bean处于活跃状态,并由外部应用程序调用使用。
  5. 销毁阶段:在容器关闭时,执行销毁方法,进行资源清理。

下面我们将详细探讨每个阶段的具体内容和机制。

Bean实例化阶段

Bean实例化是Bean生命周期的开始。在实例化阶段,Spring容器通过以下几种方式创建Bean实例:

  1. 构造函数:默认情况下,Spring会通过无参构造函数创建Bean实例。如果没有无参构造函数,可以通过@Configuration和@Bean注解来显式指定构造函数。
  2. 静态工厂方法:使用静态工厂方法创建Bean实例,需要在配置文件中指定工厂方法名。
  3. 实例工厂方法:使用实例工厂方法创建Bean实例,需要先提供一个工厂实例,再调用工厂实例方法创建Bean。

示例代码如下:

// 通过构造函数创建Bean
@Component
public class ExampleBean {public ExampleBean() {System.out.println("ExampleBean实例化!");}
}// 通过静态工厂方法创建Bean
public class StaticFactory {public static ExampleBean createInstance() {return new ExampleBean();}
}// 通过实例工厂方法创建Bean
public class InstanceFactory {public ExampleBean createInstance() {return new ExampleBean();}
}

在配置文件中配置静态工厂方法和实例工厂方法:

<bean id="exampleBeanStatic" class="com.example.StaticFactory" factory-method="createInstance"/>
<bean id="exampleBeanInstance" factory-bean="instanceFactory" factory-method="createInstance"/>
<bean id="instanceFactory" class="com.example.InstanceFactory"/>

依赖注入阶段

在实例化阶段完成后,容器会自动进行依赖注入。依赖注入有以下几种方式:

  1. 构造函数注入:通过构造函数参数注入依赖对象。
  2. Setter方法注入:通过Setter方法注入依赖对象。
  3. 字段注入:直接通过反射注入依赖对象(需要使用注解)。

构造函数注入

构造函数注入通过构造函数参数传递依赖对象:

@Component
public class ExampleService {private final ExampleRepository repository;@Autowiredpublic ExampleService(ExampleRepository repository) {this.repository = repository;}
}

Setter方法注入

Setter方法注入通过Setter方法来注入依赖对象:

@Component
public class ExampleService {private ExampleRepository repository;@Autowiredpublic void setRepository(ExampleRepository repository) {this.repository = repository;}
}

字段注入

字段注入通过直接在字段上使用@Autowired注解:

@Component
public class ExampleService {@Autowiredprivate ExampleRepository repository;
}

初始化阶段

在依赖注入完成后,Bean会进入初始化阶段。初始化阶段旨在完成Bean实例的进一步配置和准备工作。Spring提供了几种方式来定制Bean的初始化行为:

  1. 实现InitializingBean接口:通过实现afterPropertiesSet方法来定义自定义初始化逻辑。
  2. 使用@PostConstruct注解:通过在方法上使用@PostConstruct注解来定义初始化逻辑。
  3. 自定义初始化方法:在XML配置文件或注解中指定自定义的初始化方法。

实现InitializingBean接口

实现InitializingBean接口并重写afterPropertiesSet方法:

@Component
public class ExampleBean implements InitializingBean {@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("ExampleBean初始化!");}
}

使用@PostConstruct注解

在方法上使用@PostConstruct注解:

@Component
public class ExampleBean {@PostConstructpublic void init() {System.out.println("ExampleBean初始化!");}
}

自定义初始化方法

在配置文件或注解中指定初始化方法:

<bean id="exampleBean" class="com.example.ExampleBean" init-method="init"/>

或者通过@Bean注解:

@Configuration
public class AppConfig {@Bean(initMethod = "init")public ExampleBean exampleBean() {return new ExampleBean();}
}

Bean的使用

初始化完成后,Bean进入使用阶段。此时,Bean处于活跃状态,可以被其他对象或外部应用程序调用使用。在使用过程中,Bean可能会随着业务逻辑的需要进行多次方法调用或状态变更。

示例使用

@Component
public class ServiceConsumer {@Autowiredprivate ExampleService exampleService;public void performAction() {exampleService.doSomething();}
}

销毁阶段

当Bean的生命周期结束时,容器会执行销毁方法,释放资源。Spring提供了几种方式来定制Bean的销毁行为:

  1. 实现DisposableBean接口:通过实现destroy方法来定义自定义销毁逻辑。
  2. 使用@PreDestroy注解:通过在方法上使用@PreDestroy注解来定义销毁逻辑。
  3. 自定义销毁方法:在XML配置文件或注解中指定自定义的销毁方法。

实现DisposableBean接口

实现DisposableBean接口并重写destroy方法:

@Component
public class ExampleBean implements DisposableBean {@Overridepublic void destroy() throws Exception {System.out.println("ExampleBean销毁!");}
}

使用@PreDestroy注解

在方法上使用@PreDestroy注解:

@Component
public class ExampleBean {@PreDestroypublic void cleanup() {System.out.println("ExampleBean销毁!");}
}

自定义销毁方法

在配置文件或注解中指定销毁方法:

<bean id="exampleBean" class="com.example.ExampleBean" destroy-method="cleanup"/>

或者通过@Bean注解:

@Configuration
public class AppConfig {@Bean(destroyMethod = "cleanup")public ExampleBean exampleBean() {return new ExampleBean();}
}

完整的Bean生命周期流程

通过上述各个阶段的介绍,我们可以总结出Spring中Bean生命周期的完整流程:

  1. 实例化:通过构造函数或工厂方法创建Bean实例。
  2. 依赖注入:将依赖对象注入到Bean中。
  3. BeanPostProcessorpostProcessBeforeInitialization方法:在初始化之前执行。
  4. 初始化:执行自定义的初始化方法。
  5. BeanPostProcessorpostProcessAfterInitialization方法:在初始化之后执行。
  6. Bean的使用:Bean处于活跃状态,供外部调用使用。
  7. 销毁:容器关闭时,执行销毁方法,进行资源清理。

示例代码

让我们通过一个完整的示例来展示Spring中Bean的生命周期各个步骤。假设我们有一个简单的业务服务类ExampleService

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;@Component
public class ExampleService implements InitializingBean, DisposableBean {private ExampleRepository repository;@Autowiredpublic ExampleService(ExampleRepository repository) {this.repository = repository;}@PostConstructpublic void postConstruct() {System.out.println("ExampleService的postConstruct初始化!");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("ExampleService的afterPropertiesSet初始化!");}public void doSomething() {System.out.println("ExampleService在执行业务逻辑!");}@PreDestroypublic void preDestroy() {System.out.println("ExampleService的preDestroy销毁!");}@Overridepublic void destroy() throws Exception {System.out.println("ExampleService的destroy销毁!");}
}

配置类中定义Bean:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Bean(initMethod = "init", destroyMethod = "cleanup")public ExampleBean exampleBean() {return new ExampleBean();}
}

应用程序主类:

import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class MainApplication {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);ExampleService exampleService = context.getBean(ExampleService.class);exampleService.doSomething();context.close();}
}

在运行上述代码后,我们会在控制台中看到Bean的各个生命周期阶段的相关输出:

ExampleService的postConstruct初始化!
ExampleService的afterPropertiesSet初始化!
ExampleService在执行业务逻辑!
ExampleService的preDestroy销毁!
ExampleService的destroy销毁!

总结

理解Spring中Bean的生命周期是掌握Spring框架基础的重要环节。通过本文的详细介绍,我们从实例化、依赖注入、初始化、使用和销毁五个阶段全方位解析了Bean的生命周期,并通过示例代码展示了如何在实际开发中应用这些知识。希望本文能帮助您更好地理解和使用Spring框架,以构建更加高效、易维护的Java应用程序。

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

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

相关文章

word避免画质画质模糊方法

问题描述&#xff1a;   近期写文档时会高频率贴图&#xff0c;粘图过程中发现Word会自动压缩图片画质&#xff0c;而且压缩得很严重&#xff0c;下面是一幅图被压缩前后的画质对比 &#xff08;图片压缩前&#xff09; &#xff08;图片压缩后&#xff09; 解决方案&#x…

基于JSP的九宫格日志网站

你好呀&#xff0c;我是学长猫哥&#xff01;如果有需求可以文末加我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JSP技术 工具&#xff1a;浏览器/服务器&#xff08;B/S&#xff09;结构 系统展示 首页 管理员功能模块 用户功能模块 摘要 本…

GPT-4o VS GPT-3.5 完胜

前言&#xff1a; 最近&#xff0c;GPT-4o已经限时免费开放了&#xff0c;试了一下&#xff0c;然后&#xff0c;说我的时间到了&#xff0c;然后&#xff0c;有给我转到3.5&#xff0c;正好遇到一个问题做一下对吧&#xff0c;感觉4O完胜啊。3.5还是很好胡诌&#xff0c;也就…

[Algorithm][动态规划][子序列问题][最长定差子序列][最长的斐波那契子序列的长度]详细讲解

目录 1.最长定差子序列1.题目链接2.算法原理详解3.代码实现 2.最长的斐波那契子序列的长度1.题目链接2.算法原理详解3.代码实现 1.最长定差子序列 1.题目链接 最长定差子序列 2.算法原理详解 思路&#xff1a; 确定状态表示 -> dp[i]的含义 以i位置元素为结尾的所有子序列…

Python知识点3---条件判断语句

提前说一点&#xff1a;如果你是专注于Python开发&#xff0c;那么本系列知识点只是带你入个门再详细的开发点就要去看其他资料了&#xff0c;而如果你和作者一样只是操作其他技术的Python API那就足够了。 Python的条件判断语句和其他的语言有些不一样&#xff0c;它只有if语…

【从加载数据库驱动包,理解java SPI】

SPI&#xff08;Service Provider Interface&#xff09; 从1.6引入&#xff0c;基于ClassLoader 来加载并发现服务的机制 对于msyql驱动 引入依赖 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><v…

11.2 选择排序

目录 11.2 选择排序 11.2.1 算法特性 11.2 选择排序 选择排序&#xff08;selection sort&#xff09;的工作原理非常简单&#xff1a;开启一个循环&#xff0c;每轮从未排序区间选择最小的元素&#xff0c;将其放到已排序区间的末尾。 设数组的长度为 &#x1d45b;…

华东师范大学研究团队《Ecology Letters 》揭示植物如何改变其物候以响应全球变化

自工业革命以来&#xff0c;人类活动导致多种环境因子同时发生变化&#xff0c;包括气候变暖、降水模式改变、氮沉降增加和大气CO2升高。这些变化预计会影响植物生命周期事件的季节时序—植物物候&#xff08;Nature Reviews Earth & Environment | 傅伯杰院士团队发文阐述…

[C][栈帧]详细讲解

目录 1.栈帧1.进程地址空间2.栈帧说明 2.认识相关寄存器3.认识相关汇编命令4.过程理解5.栈帧总结6.补充 1.栈帧 1.进程地址空间 .进程地址空间 2.栈帧说明 调用函数&#xff0c;形成栈帧函数返回&#xff0c;释放栈帧局部变量是存放在栈区上的栈区内存的使用习惯是&#xff…

BPTT算法详解:深入探究循环神经网络(RNN)中的梯度计算【原理理解】

引言 在深度学习领域中&#xff0c;我们经常处理的是独立同分布&#xff08;i.i.d&#xff09;的数据&#xff0c;比如图像分类、文本生成等任务&#xff0c;其中每个样本之间相互独立。然而&#xff0c;在现实生活中&#xff0c;许多数据具有时序结构&#xff0c;例如语言模型…

什么是PLAB?

接上文PLAB---》 可以看到和TLAB很像&#xff0c;PLAB即 Promotion Local Allocation Buffers。用在年轻代对象晋升到老年代时。 在多线程并行执行YGC时&#xff0c;可能有很多对象需要晋升到老年代&#xff0c;此时老年代的指针就"热"起来了&#xff0c;于是搞了个…

Google Cloudbuild yaml file 中 entrypoint 和 args 的写法

编写cloudbuild.yaml 时有几个关键参数 entrypoint 和 args 的基本介绍 id: 显示在 cloud build logs 里的item 名字 name: docker 镜像名字 - 下面的命令会在这个镜像的1个容器instance 内执行 entrypoint: 执行的命令入口 &#xff0c; 只能有1个对象 args&#xff1a; 命名…

函数的创建和调用

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 提到函数&#xff0c;大家会想到数学函数吧&#xff0c;函数是数学最重要的一个模块&#xff0c;贯穿整个数学学习过程。在Python中&#xff0c;函数…

深入解析 YOLOv8 中的 `conv.py`(代码图文全解析-下)

&#x1f60e; 作者介绍&#xff1a;我是程序员行者孙&#xff0c;一个热爱分享技术的制能工人。计算机本硕&#xff0c;人工制能研究生。公众号&#xff1a;AI Sun&#xff0c;视频号&#xff1a;AI-行者Sun &#x1f388; 本文专栏&#xff1a;本文收录于《yolov8》系列专栏&…

【linux软件基础知识】与调度相关的进程描述符

进程描述符 每个进程描述符都包括几个与调度相关的字段,如下代码所示: //include/asm-arm/thread_info.h /** low level task data that entry.S needs immediate access to.* __switch_to() assumes cpu_context follows immediately after cpu_domain.*/ struct thread_in…

vite为什么速度快

原因 vite快的原因是因为 vite在开发环境中是使用的 esbuild&#xff0c;esbuild 是 go 写的&#xff0c;go 编译型语言、多线程&#xff0c;nodejs 解释型语言、单线程&#xff0c;并且 vite 使用了原生 esm 导入的&#xff0c;所以快一点&#xff0c;当然&#xff0c;这也…

6.1Java方法

1、方法定义&#xff1a; 方法是一种语法结构&#xff0c;它可以把一段代码封装成一个功能&#xff0c;以便重复调用 方法的完整格式&#xff1a; 修饰符 返回类型 方法名(形参列表){ 方法体代码(需要执行的功能代码) return 返回值; } package com.define;public class …

【缓存】框架层常见问题和对策

缓存是为了加快读写速度&#xff0c;再了解redis这类框架层的缓存应用之前&#xff0c;我们不妨先思考下操作系统层面的缓存解决方案&#xff0c;这样有助于我们更深的理解缓存&#xff0c;哪些是系统层面的&#xff0c;哪些是服务层面。 以下是一些常见的缓存问题及其解决方案…

面向对象编程 (OOP):深入理解继承、多态和抽象

1. 简介 面向对象编程 (OOP) 是一种强大的编程范式&#xff0c;它通过将程序组织成对象的集合来简化软件设计和开发。与传统的程序设计方法相比&#xff0c;OOP 提供了一种更自然、更易于理解和维护的方式来构建复杂的软件系统。OOP 的核心概念包括&#xff1a;对象、类、继承、…

Java进阶学习笔记31——日期时间

Date&#xff1a; 代表的是日期和时间。 分配Date对象并初始化它以表示自标准基准时间&#xff08;称为纪元&#xff09;以来的指定毫秒数&#xff0c;即1970年1月1日00:00:00。 有参构造器。 package cn.ensource.d3_time;import java.util.Date;public class Test1Date {pu…