Spring Bean的生命周期是什么样的?

在Spring容器里一个Bean的从创建到销毁一般都是经历了以下几个阶段:
定义阶段(Bean元信息配置)=>实例化阶段(创建Bean对象)=>初始化阶段(执行初始化逻辑)=>使用阶段(Bean可用)=>销毁阶段(释放资源)
Spring bean的生命周期

定义阶段(BeanDefinition解析)

Spring通过配置(XML、注解、Java配置)解析Bean的元数据,生成BeanDefinition对象
BeanDefinition存储了Bean的类名、作用域(scope)、依赖项(depends-on)、初始化方法、销毁方法等元数据。
所有BeanDefinition存储在容器的BeanDefinitionMap(一个HashMap)中,键为Bean名称,值为BeanDefinition对象。
解析器:

  • XML配置:XmlBeanDefinitionReader解析<bean>标签。
  • 注解配置:ClassPathBeanDefinitionScanner扫描@Component等注解。
  • Java配置:ConfigurationClassPostProcessor解析@Bean方法。

实例化阶段(创建Bean实例)

根据BeanDefinition通过反射或工厂方法创建Bean实例(对象),但此时属性未注入
默认通过无参构造方法实例化(若未指定,Spring会强制要求无参构造)。

AbstractAutowireCapableBeanFactory类中的createBeanInstance方法中实现。

属性值填充(依赖注入)

为Bean的属性设置值或注入依赖

  • 通过@Autowired@ValueXML<property>等方式注入属性。
  • 若注入的依赖是其他Bean,会递归触发依赖Bean的生命周期。
  • 循环依赖问题:在属性注入阶段处理循环依赖(通过三级缓存解决)。

AbstractAutowireCapableBeanFactorypopulateBean方法中处理。

Aware接口回调设置

若Bean实现了特定Aware接口,Spring会回调对应方法,注入容器相关对象

  • BeanNameAware:注入Bean在容器中的名称(setBeanName(String beanName))。
  • BeanFactoryAware:注入当前Bean所在的BeanFactory(setBeanFactory(BeanFactory beanFactory))。
  • ApplicationContextAware:若容器是ApplicationContext,注入应用上下文(setApplicationContext(ApplicationContext applicationContext))。

AbstractAutowireCapableBeanFactoryinitializeBean方法中调用。

BeanPostProcessor前置处理

在Bean初始化前,允许自定义BeanPostProcessor对Bean实例进行处理。
主要是调用BeanPostProcessorpostProcessBeforeInitialization方法。
常见的实现类

  • ApplicationContextAwareProcessor:处理ApplicationContextAware接口。
  • InitDestroyAnnotationBeanPostProcessor:处理@PostConstruct注解。

AbstractAutowireCapableBeanFactoryapplyBeanPostProcessorsBeforeInitialization方法执行。

InitializingBean处理以及自定义init-method处理

执行Bean的初始化逻辑。
InitializingBean处理,在所有Bean属性设置完成后进行初始化操作。如果Bean实现了InitializingBean接口,InitializingBeanafterPropertiesSet方法会被调用。

自定义init-method处理,如果Bean在配置文件中定义了初始化方法那么该方法会被调用。
例如:通过XML配置init-method或Java配置@Bean(initMethod=“xxx”)。

AbstractAutowireCapableBeanFactoryinvokeInitMethods方法中调用

BeanPostProcessor后置处理

在Bean初始化后,允许自定义BeanPostProcessor对Bean实例进行处理。
BeanPostProcessorpostProcessAfterInitialization方法会被调用。

常见用途:AOP代理(如AbstractAutoProxyCreator在此阶段为目标对象创建代理)

AbstractAutowireCapableBeanFactoryapplyBeanPostProcessorsAfterInitialization方法执行

注册DisposableBean回调

如果Bean实现了DisposableBean接口或在Bean定义中指定了自定义的销毁方法,Spring容器会为这些Bean注册一个销毁回调,确保在容器关闭时能够正确地清理资源。

AbstractAutowireCapableBeanFactory类中的registerDisposableBeanlfNecessary方法中实现

Bean使用阶段

**Bean已完全初始化,可被应用程序使用。**通过依赖注入获取Bean实例(如@AutowiredApplicationContext.getBean())。
此阶段Bean处于“可用”状态,直到容器关闭。

Bean销毁阶段

容器关闭时,释放Bean资源。
主要步骤:

  • 接口回调:若Bean实现了DisposableBean,调用destroy方法。
  • 注解:若方法标注了@PreDestroy,Spring会调用该方法。
  • 自定义销毁方法:通过XML配置destroy-method或Java配置@Bean(destroyMethod="xxx")
  • 资源释放:如关闭数据库连接、释放文件句柄等。

DisposableBeanAdapterdestroy方法中实现

总结

通过代码出处,可以观察到整个Bean的创建的过程都依赖于AbstractAutowireCapableBeanFactory这个类,而销毁主要依赖DisposableBeanAdapter这个类。
AbstractAutowireCapableBeanFactory 的入口处,doCreateBean的核心代码如下,其中包含了实例化、设置属性值、初始化Bean以及注册销毁回调的几个核心方法。
这里就不贴代码了,想更深入看细节的可以去看源码。

Spring中创建Bean的方式有哪些?

基于注解的自动扫描

通过注解标记类,并配合组件扫描实现自动注册。
常见的注解有
@Component, @Service, @Repository, @Controller(及其衍生注解)。

例如:当在类上添加@Component时,再在配置类或 XML 中启用组件扫描(@ComponentScan<context:component-scan>)。这个类在服务启动时会自动被扫描到,然后注入到Spring容器。

@Configuration
@ComponentScan("com.jimoer.service")
public class BeanConfig {}
@Service
public class UserService {public void hello() {System.out.println("Hello from UserService");}
}@Component
public class UserHandler {public void hello() {System.out.println("Hello from UserHandler");}
}@Repository
public class UserRepository {public void hello() {System.out.println("Hello from UserRepository");}
}@Controller
public class UserController {public void hello() {System.out.println("Hello from UserController");}
}

使用@Configuration与@Bean 注解

通过 @Configuration 标注的配置类,显式定义 Bean 的创建逻辑。
适用于:需要精确控制 Bean 的初始化逻辑(如依赖其他 Bean 或复杂条件)。

@Configuration
public class AppConfig {@Beanpublic UserService userService() {return new UserService();}
}

XML 配置文件

通过 xml 的方式来定义 Bean。
在SpringBoot 流行以前,这种方式挺多的, SpringBoot 流行起来之后,这么用的越来越少了。

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"<bean id="userService" class="com.jimoer.demo.UserServiceImpl"><property name="message" value="Hello Spring!" /></bean>
</beans>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService");

更适用于遗留项目或需要与非注解配置兼容的场景。

使用@Import注解

@Import注解的作用是快速导入某一个或多个类,使这些类能够被Spring加载到IOC容器中进行管理。
让类被Spring 的 IOC 容器管理,这不也是创建 Bean 么,因此,这种方式也可以算是创建Bean的一种方式。

@Import({UserServiceImpl.class})
@Configuration
public class UserBeanConfiguration {
}

自定义注解

通过自定义一种注解,然后在 Spring 应用启动过程中,通过自定义的 BeanDefinitionRegistryPostProcessorBeanfactoryPostProcessor 来扫描配置的包路径,识别出带有自定义注解的类。
这些处理器解析注解中的属性(如接口类、版本号、超时时间等),并基于这些信息创建 Spring的 BeanDefinition
例如:Dubbo框架使用的@DubboService注解

@DubboService("version=1.0.0")
public class UserServiceImpl implements UserFacadeService {}

动态注册(运行时注册)

在运行时通过 BeanDefinitionRegistry 动态注册 Bean。

// 获取 BeanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();// 定义 Bean 的元数据
GenericBeanDefinition userDefinition = new GenericBeanDefinition();
userDefinition.setBeanClass(UserService.class);// 注册 Bean
beanFactory.registerBeanDefinition("userService", userDefinition);

适用于:根据运行时条件动态生成 Bean(如插件化系统、动态配置)。

Spring Bean的注入方式有哪些?

使用@Autowired注解

@Autowired注解是Spring框架提供的一个注解,支持多种方式自动将Spring的bean注入到其他Bean中。

字段注入
@Component
public class JimoerUserService {@Autowiredprivate UserRepository userRepository;
}
构造方法注入
@Component
public class JimoerUserService {private final UserRepository userRepository;// Spring 4.3+ 可省略 @Autowired(单构造器)@Autowiredpublic JimoerUserService(UserRepository userRepository) {this.userRepository = userRepository;}
}
setter注入
@Component
public class JimoerUserService {private UserRepository userRepository;@Autowiredpublic void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}
}

使用@Resource和@Inject注解

除了Spring提供的注解,JDK也提供了可以互相注入Bean的注解,有@Resource@Inject

@Component
public class JimoerUserService {@Resourceprivate UserRepository userRepository;
}@Component
public class JiomerUserService {@Injectprivate UserRepository userRepository;
}

使用XML配置注入

如何不使用注解注入,还可以使用XML文件的配置进行Bean的互相注入。

<bean id="userRepository" class="com.jimoer.UserRepository"/>
<!-- 构造方法注入 -->
<bean id="userService" class="com.jiomer.UserService"><constructor-arg ref="userRepository"/>
</bean>
<!-- 字段注入 -->
<bean id="jimoerUserService" class="com.jiomer.JimoerUserService"><property name="userRepository" ref="userRepository"/>
</bean>

构造方法自动注入

其实从 Spring 4.3 开始,除非一个类中声明了至少两个构造函数,否则不需要用 @Autowired 标注构造函数,这个构造函数也能直接注入 Bean。

@Component
public class JimoerUserService {private UserRepository userRepository;public JimoerUserService(UserRepository userRepository){this.userRepository=userRepository;}
}

Spring Bean的作用域有哪些?

Spring的Bean的作用域,就是指这个Bean在哪个范围内可以被使用。
不同的作用域决定了Bean的创建管理和销毁的方式。

常见的作用域有SingletonPrototypeRequestSessionApplication这五种。
在代码中,可以在定义一个Bean的时候,通过@Scope 注解来指定他的作用域。

如果没有指定Bean的作用域,默认是Singleton(单例)。

Singleton(单例)

  • 周期:Spring 容器启动时创建实例,容器关闭时销毁。
  • 作用域:每个Spring IOC容器,只创建一个Bean实例。
  • 适用于:无状态服务(如工具类、缓存管理器、数据库连接池)。
  • 线程安全:需注意,若 Bean 有可变状态(即Bean中存在线程共享变量),需通过同步机制或线程安全集合处理。
  • 配置方式:
@Component // 默认即为 singleton
public class SingletonBean {
}

Propertype(原型)

  • 周期:每次调用 getBean() 或注入时创建新实例,容器不负责销毁。
  • 适用于:有状态 Bean(如用户会话数据、临时对象)。
  • 线程安全:实例独立,避免线程安全问题。
  • 配置方式:
@Component
@Scope("prototype")
public class PrototypeBean {
}

Request(HTTP 请求)

  • 周期:每个 HTTP 请求创建一个实例,请求结束后销毁。
  • 适用于:Web 应用中请求级别的数据共享(如请求日志、上下文信息)。

仅适用于 Web 应用环境。

  • 配置方式:
@Component
@Scope("request")
public class RequestBean {
}

Session(HTTP 会话)

  • 周期:每个用户会话(HttpSession)创建一个实例,会话结束时销毁。
  • 适用于:用户会话数据(如购物车、用户偏好设置)。

仅适用于 Web 应用环境。

  • 配置方式:
@Component
@Scope("session")
public class SessionBean {
}

Application(应用)

  • 周期:Web 应用启动时创建实例,应用关闭时销毁。
  • 适用于:全局配置或共享资源(如应用级缓存、配置信息)。类似 singleton,但绑定到 ServletContext

仅适用于 Web 环境

  • 配置方式:
@Component
@Scope("application")
public class ApplicationBean {
}

Websocket(WebSocket 会话)

  • 周期:WebSocket 连接建立时创建实例,连接关闭时销毁。
  • 适用于:WebSocket 会话上下文数据(如实时通信状态)。

仅适用于 WebSocket 应用。

  • 配置方式:
@Component
@Scope("websocket")
public class WebSocketBean {
}

自定义作用域

一般情况下,在开发过程中,都是使用Singleton作用域,有时候也会用Propertype,其他几个用的都不多。但是除了上面列举的6个Spring提供作用域以外,还可以自己定义Bean作用域。

自定义一个Spring Bean的作用域,需要实现org.springframework.beans.factory.config.Scope接口,主要是实现如下几个方法来管理Bean的生命周期。

package org.springframework.beans.factory.config;import org.springframework.beans.factory.ObjectFactory;public interface Scope {Object get(String var1, ObjectFactory<?> var2);Object remove(String var1);void registerDestructionCallback(String var1, Runnable var2);Object resolveContextualObject(String var1);String getConversationId();
}

自定义一个类,然后实现Scope接口,来实现我们自己的Bean作用域。

public class JimoerScope implements Scope{@Overridepublic Object get(String s, ObjectFactory<?> objectFactory) {// 获取Bean的逻辑return objectFactory.getObject();}@Overridepublic Object remove(String s) {// 移除Bean的逻辑return null;}@Overridepublic void registerDestructionCallback(String s, Runnable runnable) {// 注册Bean销毁时的回调}@Overridepublic Object resolveContextualObject(String s) {// 解析上下文return null;}@Overridepublic String getConversationId() {// 获取会话IDreturn "";}
}

接下来,我们将Spring配置中注册这个自定义的作用域。
这可以通过ConfigurableBeanFactory.registerScope 方法实现。

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Beanpublic JimoerScope jimoerScope(ConfigurableBeanFactory beanFactory) {JimoerScope jimoerScope = new JimoerScope();beanFactory.registerScope("jimoer", jimoerScope);return jimoerScope;}}

此时在Bean定义中使用自定义的作用域的名称jimoer
Spring 容器将会根据你的自定义逻辑来创建和管理这些 Bean。

@Component
@Scope("jimoer")
public class CustomerScopeTest {
}

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

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

相关文章

SpringSecurity的应用

官方文档 一、核心能力 1.1 身份认证 (Authentication) - “你是谁&#xff1f;” 多种认证方式&#xff1a;支持几乎所有主流认证方案&#xff0c;如表单登录&#xff08;Username/Password&#xff09;、HTTP Basic、HTTP Digest、OAuth 2.0、OIDC (OpenID Connect)、SAML …

跨境云手机与传统手机的不同之处

传统手机主要满足个人日常生活中的通讯、娱乐、办公等基础需求&#xff0c;比如用于日常打电话联系亲朋好友&#xff0c;闲暇时刷短视频、玩本地安装的游戏&#xff0c;或者简单处理一些文档、邮件等办公事务。跨境云手机主要是侧重于跨境业务场景&#xff0c;对于从事跨境电商…

MemGPT: Towards LLMs as Operating Systems

1 MemGPT: Towards LLMs as Operating Systems 论文地址&#xff1a;MemGPT: Towards LLMs as Operating Systems 代码地址&#xff1a;https://github.com/letta-ai/letta 1.1 MemGPT MemGPT&#xff08;MemoryGPT&#xff09;借鉴传统操作系统的分层内存管理思想&#xff08;…

MICAPS:气象信息综合分析与处理系统概述

1.概述 说明:Meteorological Information Comprehensive Analysis and Process System 中文意思:气象信息综合分析处理系统。它是中国气象局开发的一套气象数据分析、处理和可视化系统,用于气象资料的收集、整理、分析和发布。 2.MICAPS 的用途 说明: 数据收集:接收来自…

MySQL-day2_02

MySQL-day2&#xff08;四&#xff09;排序&#xff08;五&#xff09;聚合函数一、count 总记录数二、max 最大值三、min 最小值四、sum 求和五、avg 平均值&#xff08;六&#xff09;数据分组一、分组二、分组后的数据筛选&#xff08;七&#xff09;数据分页显示一、获取部…

HarmonyOS应用开发:深入ArkUI声明式开发范式与最佳实践

HarmonyOS应用开发&#xff1a;深入ArkUI声明式开发范式与最佳实践 引言 随着HarmonyOS 4.0的发布及API 12的推出&#xff0c;华为的分布式操作系统进入了全新的发展阶段。ArkUI作为HarmonyOS应用开发的核心框架&#xff0c;其声明式开发范式&#xff08;Declarative Paradigm&…

Claude-Flow AI协同开发:钩子系统与 GitHub 集成

5.1 思维认知框架&#xff1a;从“开发助手”到“DevOps 智能体” 在此之前&#xff0c;我们将 Claude-Flow 视为一个强大的 “开发助手 (Development Assistant)” &#xff0c;它在编码、测试、重构等环节为我们提供支持。现在&#xff0c;我们需要再次进行思维升级&#xff…

DigitalOcean Kubernetes 现已支持 Gateway API 托管服务

在 DigitalOcean Kubernetes 集群中管理流量&#xff0c;一直以来主要依赖 Ingress。虽然能满足基本需求&#xff0c;但在灵活性、角色分离和高级路由方面仍存在局限。今天&#xff0c;我们很高兴迎来新的改变。 我们正式宣布&#xff0c;Kubernetes Gateway API 托管服务现已…

聚铭网络入选数世咨询《中国数字安全价值图谱》“日志审计”推荐企业

近日&#xff0c;国内知名数字安全咨询机构数世咨询正式发布《中国数字安全价值图谱》。聚铭网络凭借领先的技术实力与出色的市场表现&#xff0c;成功入选“日志审计”领域重点推荐企业&#xff0c;彰显了在该赛道的专业认可与品牌影响力。关于《中国数字安全价值图谱》 在当下…

豆包、Kimi、通义千问、DeepSeek、Gamma、墨刀 AI”六款主流大模型(或 AI 平台)生成 PPT 的完整流程

、先厘清 3 个概念&#xff0c;少走弯路大模型 ≠ PPT 软件豆包、Kimi、通义千问、DeepSeek 本身只负责“出大纲/出文案”&#xff0c;真正的“一键配图排版”要靠官方 PPT 助手或第三方平台&#xff08;博思 AiPPT、迅捷 AiPPT、Gamma、墨刀 AI 等&#xff09;。两条主流技术路…

Redis哈希(Hash):适合存储对象的数据结构,优势与坑点解析

Redis哈希&#xff08;Hash&#xff09;&#xff1a;适合存储对象的数据结构&#xff0c;优势与坑点解析 1. Redis哈希概述 1.1 什么是Redis哈希 Redis哈希&#xff08;Hash&#xff09;是一种映射类型&#xff08;Map&#xff09;&#xff0c;由多个字段值对&#xff08;fi…

Python的uv包管理工具使用

一、简介 uv是一个继Python版本管理、Python包管理、项目管理、虚拟环境管理于一体的工具&#xff0c;由于底层是用Rust编写的&#xff0c;uv的执行速度非常快。 安装 pip install uv镜像源设置 uv默认安装包是从pypi上下载的&#xff0c;速度比较慢。我们可以设置镜像源&#…

JavaScript事件机制与性能优化:防抖 / 节流 / 事件委托 / Passive Event Listeners 全解析

目标&#xff1a;把“为什么慢、卡顿从哪来、该怎么写”一次说清。本文先讲事件传播与主线程瓶颈&#xff0c;再给出四件法宝&#xff08;防抖、节流、事件委托、被动监听&#xff09;&#xff0c;最后用一套可复制的工具函数 清单收尾。1&#xff09;先理解“为什么会卡”&am…

【Chrome】chrome 调试工具的network选项卡,如何同时过滤出doc js css

通过类型按钮快速筛选&#xff08;更直观&#xff09;在 Network 选项卡中&#xff0c;找到顶部的 资源类型按钮栏&#xff08;通常在过滤器搜索框下方&#xff09;。按住 Ctrl 键&#xff08;Windows/Linux&#xff09;或 Command 键&#xff08;Mac&#xff09;&#xff0c;同…

Elasticsearch (ES)相关

在ES中&#xff0c;已经有Term Index&#xff0c;那还会走倒排索引吗 你这个问题问得很到位 &#x1f44d;。我们分清楚 Term Index 和 倒排索引 在 Elasticsearch (ES) 里的关系&#xff1a;1. 倒排索引&#xff08;Inverted Index&#xff09; 是 Lucene/ES 检索的核心。文档…

pre-commit run --all-files 报错:http.client.RemoteDisconnected

报错完整信息初步原因是这样 报错是 Python 的 http.client.RemoteDisconnected&#xff0c;意思是 在用 urllib 请求远程 URL 时&#xff0c;远程服务器直接断开了连接&#xff0c;没有返回任何响应。在你的堆栈里&#xff0c;它出现在 pre-commit 尝试安装 Golang 环境的时候…

【C++】STL·List

1. list的介绍及使用 1.1list介绍 List文档介绍 1.2 list的使用 list中的接口比较多&#xff0c;此处类似&#xff0c;只需要掌握如何正确的使用&#xff0c;然后再去深入研究背后的原理&#xff0c;已 达到可扩展的能力。以下为list中一些常见的重要接口。 1.2.1 list的构造…

图论2 图的数据结构表示

目录 一 图的数据结构表示 1 邻接矩阵&#xff08;Adjacency Matrix&#xff09; 2 邻接表&#xff08;Adjacency List&#xff09; 3 边列表&#xff08;Edge List&#xff09; 4 十字链表&#xff08;Orthogonal List / Cross-linked List, 十字链表&#xff09; 5 邻接…

在Excel中删除大量间隔空白行

在 Excel 中删除大量间隔空白行&#xff0c;可使用定位空值功能来快速实现。以下是具体方法&#xff1a;首先&#xff0c;选中包含空白行的数据区域。可以通过点击数据区域的左上角单元格&#xff0c;然后按住鼠标左键拖动到右下角最后一个单元格来实现。接着&#xff0c;按下快…

【C 学习】10-循环结构

“知道做不到就是不知道”一、条件循环1. while只要条件为真&#xff08;true&#xff09;&#xff0c;就会重复执行循环体内的代码。while (条件) {// 循环体&#xff08;要重复执行的代码&#xff09; }//示例 int i 1; while (i < 5) {printf("%d\n", i);i; …