当前位置: 首页 > news >正文

技术面:Spring (bean的生命周期、创建方式、注入方式、作用域)

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.wxhsa.cn/company.asp?id=3060

相关文章:

  • 马尔可夫决策
  • 十九、指令流水线的基本概念
  • 本地布署Diffusers库 实现文生图 - yi
  • 【光照】[光照模型]发展里程碑时间线
  • 算法设计作业-week1
  • git merge
  • C语言学习
  • Ubuntu 的剪贴板
  • IDAPro--MCP详细配置教程
  • 20250913 NFLS 模拟赛 部分题目
  • 帐号内容定位
  • 基于YOLOv8的茶叶病害识别项目|完整源码数据集+图形化界面+训练教程
  • 2025第三届“陇剑杯”网络安全大赛初赛-夺旗闯关赛wp
  • 《Python数据结构与算法分析》第二弹《2.2.2 异序词检测示例》
  • 深入解析:柱状图(Vue3)
  • 计算机毕业设计springboot基于微信小程序的手机点餐软件 基于Spring Boot框架的微信小程序点餐体系设计与实现 微信小脚本点餐应用开发:Spring Boot技术的应用
  • 二叉树的相关知识
  • 原假设的选择准则:总损失视角的假设检验
  • dfs序基础+树上差分
  • Python中的if __name__ == __main__是什么?
  • 钻石
  • 随机游走理解
  • 【基于协同过滤的校园二手交易强大的平台】
  • Neural ODE原理与PyTorch实现:深度学习模型的自适应深度调节
  • PKU_Compiler
  • lc1026-节点与其祖先之间的最大差值
  • 如何绕过谷歌反爬策略爬取搜索结果
  • 求细胞数量
  • [SSL]
  • Rust 生命周期详解 - 实践