跳到主要内容
Spring Bean 作用域、生命周期与自动装配源码解析 | 极客日志
Java java
Spring Bean 作用域、生命周期与自动装配源码解析 综述由AI生成 Spring Bean 作用域定义了实例在容器中的可见范围,包括单例、原型、请求、会话及应用等。生命周期涵盖实例化、属性赋值、初始化、使用及销毁五个阶段,涉及 Aware 接口、BeanPostProcessor 及 InitializingBean 等回调机制。自动装配通过约定大于配置原则,利用 @ComponentScan、@Import 及 META-INF 配置文件动态加载 Bean,减少手动配置复杂度。文章结合源码解析了 AbstractAutowireCapableBeanFactory 的创建流程及日志顺序差异原因。
古灵精怪 发布于 2026/3/29 更新于 2026/6/4 26 浏览Spring Bean 作用域、生命周期与自动装配源码解析
Spring Boot 版本:3.5.8
1. Bean 的作用域
Spring Bean 的作用域定义了 Bean 的作用范围,即 Bean 在哪些上下文中可用。
public class Dog {}
@Configuration
public class DogConfig {
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public Dog singleDog () {
return new Dog ();
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Dog prototypeDog () {
return new Dog ();
}
@Bean
@RequestScope
public Dog requestDog () {
return new Dog ();
}
@Bean
@SessionScope
public Dog sessionDog () {
return new Dog ();
}
Dog {
();
}
}
{
{
SpringApplication.run(SpringPrincipleApplication.class, args);
}
}
{
Dog single;
Dog prototype;
Dog request;
Dog session;
Dog application;
ApplicationContext context;
{
.single = single;
.prototype = prototype;
.request = request;
.session = session;
.application = application;
.context = context;
}
String {
(Dog) context.getBean( );
+ .single.toString() + + + singleDog;
}
String {
(Dog) context.getBean( );
+ .prototype.toString() + + + prototypeDog;
}
String {
(Dog) context.getBean( );
+ .request.toString() + + + requestDog;
}
String {
(Dog) context.getBean( );
+ .session.toString() + + + sessionDog;
}
String {
(Dog) context.getBean( );
+ .application.toString() + + + applicationDog;
}
}
@Bean
@ApplicationScope
public
applicationDog
()
return
new
Dog
@SpringBootApplication
public
class
SpringPrincipleApplication
public
static
void
main
(String[] args)
@RequestMapping("/test")
@RestController
public
class
TestController
private
final
private
final
private
final
private
final
private
final
private
final
public
TestController
(@Qualifier("singleDog") Dog single,
@Qualifier("prototypeDog") Dog prototype,
@Qualifier("requestDog") Dog request,
@Qualifier("sessionDog") Dog session,
@Qualifier("applicationDog") Dog application,
ApplicationContext context)
this
this
this
this
this
this
@RequestMapping("/single")
public
single
()
Dog
singleDog
=
"singleDog"
return
"dog: "
this
"<br>"
"contextDog: "
@RequestMapping("/prototype")
public
prototype
()
Dog
prototypeDog
=
"prototypeDog"
return
"dog: "
this
"<br>"
"contextDog: "
@RequestMapping("/request")
public
request
()
Dog
requestDog
=
"requestDog"
return
"dog: "
this
"<br>"
"contextDog: "
@RequestMapping("/session")
public
session
()
Dog
sessionDog
=
"sessionDog"
return
"dog: "
this
"<br>"
"contextDog: "
@RequestMapping("/application")
public
application
()
Dog
applicationDog
=
"applicationDog"
return
"dog: "
this
"<br>"
"contextDog: "
直接通过 context.getBean() 获取会触发新实例创建
当使用 @Autowired 或 @Resource 注入 prototype 作用域的 Bean 时:注入操作仅在初始化阶段(Spring 容器创建和配置 Bean 的过程)执行一次,后续通过字段引用访问的是最初注入的实例,不会因后续请求自动重新注入新实例
代理注入 :当使用 @Autowired 注入 Request 作用域的 Bean 时,Spring 实际上注入的是一个代理对象而非真实实例。代理对象在应用启动时就被注入到依赖它的单例 Bean 中,但真实实例的创建被延迟到 HTTP 请求发生时
方法调用 :注入的代理对象内部持有对当前 HTTP 请求上下文的引用。当调用代理对象的方法时,代理会从当前请求的上下文中查找或创建新的真实实例
实例操作 :虽然依赖注入发生在容器初始化阶段,但通过代理模式将实例的获取延迟到实际方法调用时,这种延迟查找机制确保每个请求线程都能获得独立的实例
Application(应用) :整个 Web 应用共享一个 Bean 实例
Session(会话) :每个用户会话创建一个 Bean 实例,仅在 Web 应用中有效
Request(请求) :每个 HTTP 请求创建一个新的 Bean 实例,仅在 Web 应用中有效
Prototype(原型) :每次请求 Bean 时都会创建一个新的实例
Singleton(单例) :默认作用域,每个 Spring 容器中仅存在一个 Bean 实例
2. Bean 的生命周期 生命周期指的是一个对象从创建到销毁的整个生命过程。Bean 的生命周期分为以下 5 个部分:
实例化 :容器通过反射调用 Bean 的构造器创建对象实例
属性赋值 :容器注入依赖的属性值(例如 @Autowired)
初始化 :
通知方法调用 :通过特定接口(如 Spring 的 BeanNameAware)注入框架相关依赖或上下文信息
前置处理 :进行准备工作,例如参数校验、资源加载或权限检查。确保主逻辑具备执行条件,避免运行时错误
初始化回调 :在对象初始化阶段触发的自定义逻辑(如实现 InitializingBean 接口的 afterPropertiesSet 方法)。用于完成属性设置后的额外初始化操作
后置处理 :在流程结束后执行清理或结果处理(如 AOP 中的 @After 通知)
使用 Bean :Bean 进入就绪状态,可被应用程序调用
销毁 Bean :容器关闭时触发销毁
2.1 示例
public class Cat {}
@Configuration
public class CatConfig {
@Bean
public Cat cat () {
return new Cat ();
}
}
@Component
@Slf4j
public class BeanLifeComponent implements BeanNameAware , BeanPostProcessor, InitializingBean {
private Cat cat;
public BeanLifeComponent () {
log.info("1.实例化:执行构造方法" );
}
@Autowired
public void setCat (Cat cat) {
log.info("2.属性赋值:执行 setter 方法" );
this .cat = cat;
}
@Override
public void setBeanName (String name) {
log.info("3.1 通知方法调用,bean name is {}" , name);
}
@Override
public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException {
log.info("3.3 前置处理,bean:{},beanName:{}" , bean, beanName);
return BeanPostProcessor.super .postProcessBeforeInitialization(bean, beanName);
}
@Override
public void afterPropertiesSet () {
log.info("3.2 初始化回调" );
}
@Override
public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException {
log.info("3.4 后置处理,bean:{},beanName:{}" , bean, beanName);
return BeanPostProcessor.super .postProcessAfterInitialization(bean, beanName);
}
public void use () {
log.info("4.使用 Bean" );
}
@PreDestroy
public void preDestroy () {
log.info("5.销毁 Bean" );
}
}
@SpringBootTest
class SpringPrincipleApplicationTests {
private final ApplicationContext context;
@Autowired
public SpringPrincipleApplicationTests (ApplicationContext context) {
this .context = context;
}
@Test
public void test () {
BeanLifeComponent beanLifeComponent = context.getBean(BeanLifeComponent.class);
beanLifeComponent.use();
}
}
日志显示的顺序是:invokeInitMethods(初始化回调) applyBeanPostProcessorsBeforeInitialization(前置处理) applyBeanPostProcessorsAfterInitialization(后置处理)
这看起来与我上述介绍的生命周期流程相矛盾,具体解释放在源码解析后
2.2 源码解析
AbstractAutowireCapableBeanFactory 类的作用:主要负责 Bean 的创建、依赖注入以及初始化等生命周期管理
搜索 AbstractAutowireCapableBeanFactory 类,并找到它的 createBean 方法
doCreateBean 方法中依次调用了 createBeanInstance、populateBean 和 initializeBean 方法
3.3 初始化:initializeBean 方法中依次调用了 invokeAwareMethods、applyBeanPostProcessorsBeforeInitialization、invokeInitMethods 和 applyBeanPostProcessorsAfterInitialization 方法
createBean 方法中调用了 doCreateBean 方法
2.3 日志与源码'冲突'的原因分析 根据源码来看,正确的生命周期流程是:前置处理 → 初始化回调 → 后置处理。与上述我运行输出的日志相矛盾
关键点:BeanPostProcessor 本身也是 Bean,当 Spring 初始化一个 BeanPostProcessor 实现类 (BeanLifeComponent 类) 时,这个过程是递归的
创建非 BeanPostProcessor Bean(BeanLifeComponent 类):
按照源码顺序正常执行:BeforeInitialization → InitMethods → AfterInitialization
创建 BeanPostProcessor Bean 时:
Spring 需要先让这个 BeanPostProcessor 对象本身完成初始化 (调用 invokeInitMethods)
然后才能将它加入到 BeanPostProcessor 列表中,供后续其他 Bean(BeanLifeComponent 类) 使用
但对于这个 BeanPostProcessor Bean 自己来说:
它自己的 afterPropertiesSet 方法会在 invokeInitMethods 中执行 (初始化回调阶段)
但它自己的 postProcessBeforeInitialization(前置处理)/postProcessAfterInitialization(后置) 方法不会在它自己的创建过程中被调用!
上述日志中的情况解释:日志显示的是 一个 BeanPostProcessor 实现类 (BeanLifeComponent 类) 的初始化过程:
3.2 初始化回调 - 这个 BeanPostProcessor Bean 自己的 afterPropertiesSet()
3.3 前置处理 - BeanLifeComponent 类对这个 BeanPostProcessor Bean 的处理
3.4 后置处理 - BeanLifeComponent 类对这个 BeanPostProcessor Bean 的处理
3. SpringBoot 自动装配 作用:自动注册 Bean 到 Spring 容器,不需要手动配置,通过约定大于配置 的方式减少手动配置的复杂性。换言之,SpringBoot 的自动配置就是将依赖 Jar 包中的配置类 以及Bean 加载到Ioc 容器 的过程
3.1 SpringBoot 加载 Bean
在 pom.xml 文件中引入第三方依赖,实际上就是将第三方代码引入到 SpringBoot 项目中。SpringBoot 项目在启动时能识别这些依赖并自动将它们的配置类以及 Bean 加载到 Ioc 容器的过程。下面,我将编写代码作为第三方依赖,深入解析 SpringBoot 加载 Bean 的原理
错误日志解析:Spring 通过 五大注解 + @Bean 可以将 Bean 加载到 Ioc 容器中,前提是这些注解类需要保证和 SpringBoot 启动类 (@SpringBootApplication) 在同一目录或者其子目录下
@Slf4j
@Component
public class TestConfig {
public void demo () {
log.info("demo" );
}
}
@SpringBootTest
public class SpringPrincipleApplicationTests {
private final ApplicationContext context;
@Autowired
public SpringPrincipleApplicationTests (ApplicationContext context) {
this .context = context;
}
@Test
public void demo () {
TestConfig testConfig = context.getBean(TestConfig.class);
testConfig.demo();
}
}
3.1.1 @ComponentScan 作用:告诉 Spring 容器去哪里扫描那些被 @Component、@Service、@Repository、@Controller 等注解标记的类,并将它们自动注册为 Bean
@SpringBootApplication
@ComponentScan("com.example.springprincicle.component")
public class SpringPrincipleApplication {
public static void main (String[] args) {
SpringApplication.run(SpringPrincipleApplication.class, args);
}
}
3.1.2 @Import 作用:用于将一个或多个配置类、组件类或其他类导入到当前的 Spring 应用上下文中
@Slf4j
@Component
public class DemoConfig {
public void demo () {
log.info("demo" );
}
}
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String []{"com.example.springprincicle.component.TestConfig" , "com.example.springprincicle.component.DemoConfig" };
}
}
@SpringBootTest
public class SpringPrincipleApplicationTests {
private final ApplicationContext context;
@Autowired
public SpringPrincipleApplicationTests (ApplicationContext context) {
this .context = context;
}
@Test
public void demo () {
TestConfig testConfig = context.getBean(TestConfig.class);
testConfig.demo();
DemoConfig demoConfig = context.getBean(DemoConfig.class);
demoConfig.demo();
}
}
@SpringBootApplication
@Import(TestConfig.class)
public class SpringPrincipleApplication {
public static void main (String[] args) {
SpringApplication.run(SpringPrincipleApplication.class, args);
}
}
3.1.3 自定义注解 在使用 @Import 注解导入 Bean 时,需要程序员熟悉第三方依赖的所有配置类、组件类或其他类,这对于程序员开发程序十分不友好。所以,应该由依赖的开发者来做这件事
比较常见的方案就是第三方依赖给我们提供一个注解,该注解内部封装 @Import 注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)
public @interface EnableTestConfig {}
@SpringBootApplication
@EnableTestConfig
public class SpringPrincipleApplication {
public static void main (String[] args) {
SpringApplication.run(SpringPrincipleApplication.class, args);
}
}
3.2 @SpringBootApplication 源码解析
@SpringBootApplication 是一个组合注解,包含以下三个核心注解的功能
3.2.1 @ComponentScan
排除不需要扫描的配置类,防止自动配置类被重复扫描或注册
在 @SpringBootApplication 注解中,@ComponentScan 注解没有指定扫描路径,那么默认扫描路径为 @SpringBootApplication 标注的类的类路径
3.2.2 @SpringBootConfiguration
标记该类为 Spring 的配置类
@Indexed:为 Spring 的组件扫描提供索引支持,加速应用启动时的类加载过程
3.2.3 @EnableAutoConfiguration
AutoConfigurationImportSelector 类:它实现了 DeferredImportSelector 接口,负责在 Spring 应用启动时动态加载自动配置类
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry (AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry (configurations, exclusions);
}
fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions):体现了Spring Framework/Spring Boot 的向后兼容性设计。即使在 Spring Boot 3.x 中引入了新的 .imports 机制,Spring Framework 仍然保留了 spring.factories 的支持
private void fireAutoConfigurationImportEvents (List<String> configurations, Set<String> exclusions) {
List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
if (!listeners.isEmpty()) {
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent (this , configurations, exclusions);
for (AutoConfigurationImportListener listener : listeners) {
invokeAwareMethods(listener);
listener.onAutoConfigurationImportEvent(event);
}
}
}
protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners () {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this .beanClassLoader);
}
public static <T> List<T> loadFactories (Class<T> factoryType, @Nullable ClassLoader classLoader) {
return forDefaultResourceLocation(classLoader).load(factoryType);
}
public static SpringFactoriesLoader forDefaultResourceLocation (@Nullable ClassLoader classLoader) {
return forResourceLocation(FACTORIES_RESOURCE_LOCATION, classLoader);
}
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories" ;
遵循 Spring Boot 的"约定优于配置"理念,第三方依赖库需要将其自动配置类定义在 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中,这样 Spring Boot 启动时就能自动发现并加载这些配置
getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes):在 Spring Boot 3.5.8(本文所用的版本) 中,该方法不仅加载 Spring Boot 默认的自动配置类,还会加载所有第三方库提供的自动配置类
protected List<String> getCandidateConfigurations (AnnotationMetadata metadata, AnnotationAttributes attributes) {
ImportCandidates importCandidates = ImportCandidates.load(this .autoConfigurationAnnotation, getBeanClassLoader());
List<String> configurations = importCandidates.getCandidates();
Assert.state(!CollectionUtils.isEmpty(configurations), "No auto configuration classes found in " +
"META-INF/spring/" + this .autoConfigurationAnnotation.getName() + ".imports. If you " +
"are using a custom packaging, make sure that file is correct." );
return configurations;
}
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online