1. Spring Bean 生命周期全流程拆解
Spring 容器中一个 Bean 从创建到销毁的完整生命周期包含多个关键阶段,每个阶段都有其特定的执行逻辑和扩展点。理解这些阶段对于掌握 Spring 框架的核心机制至关重要。
1.1 定义阶段:BeanDefinition 的解析与注册
在 Spring 容器启动时,首先会解析各种配置源(XML、注解、Java Config)来获取 Bean 的元数据信息。这个阶段的核心产物是 BeanDefinition 对象,它包含了 Bean 的类名、作用域、懒加载标志、依赖关系等所有配置信息。
解析过程由不同的 Reader 和 Scanner 完成:
- XmlBeanDefinitionReader 处理 XML 配置
- ClassPathBeanDefinitionScanner 扫描 @Component 等注解
- ConfigurationClassPostProcessor 处理 @Configuration 类
这些解析器会将解析结果注册到 DefaultListableBeanFactory 的 beanDefinitionMap 中,这是一个 ConcurrentHashMap,键为 beanName,值为对应的 BeanDefinition 对象。
实际开发中,我们经常会遇到 BeanDefinitionOverrideException,这就是因为同一个 beanName 被重复注册导致的。Spring Boot 2.1 之后默认不允许覆盖,可以通过 spring.main.allow-bean-definition-overriding=true 来允许覆盖。
1.2 实例化阶段:对象的创建策略
当容器需要创建一个 Bean 实例时,会进入实例化阶段。这个阶段主要通过反射机制调用构造方法来创建对象实例。Spring 提供了多种实例化策略:
- 构造方法实例化:默认使用无参构造,如果有多个构造方法,Spring 会根据依赖情况选择最合适的构造方法
- 静态工厂方法:通过 factory-method 指定静态方法
- 实例工厂方法:通过 factory-bean + factory-method 指定
实例化的核心代码在 AbstractAutowireCapableBeanFactory.createBeanInstance() 方法中。这里有个重要的设计:Spring 会先尝试用默认构造方法,如果失败再尝试其他构造方法。
java复制// 简化版的实例化逻辑
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
1.3 属性填充与依赖注入
实例化完成后,Spring 会进行属性填充(依赖注入)。这个过程主要处理 @Autowired、@Value 等注解标注的字段和方法。Spring 的依赖注入遵循以下顺序:
- 处理 @Autowired 注解的字段
- 处理 @Autowired 注解的方法
- 处理 XML 中配置的
元素
循环依赖是这一阶段常见的问题。Spring 通过三级缓存机制解决 setter 注入的循环依赖:
- 一级缓存:singletonObjects,存放完全初始化好的 Bean
- 二级缓存:earlySingletonObjects,存放早期对象(已实例化但未完成初始化的 Bean)
- 三级缓存:singletonFactories,存放 ObjectFactory
构造器注入的循环依赖无法解决,因为构造器注入需要在实例化时就完成依赖注入,此时 Bean 还未放入缓存中。
1.4 初始化阶段:回调与扩展点
初始化阶段是 Bean 生命周期中最复杂的阶段,包含多个重要的扩展点:
-
Aware 接口回调:
- BeanNameAware:设置 beanName
- BeanFactoryAware:设置 BeanFactory
- ApplicationContextAware:设置 ApplicationContext
-
BeanPostProcessor 前置处理:
- postProcessBeforeInitialization 方法
- 典型应用:@PostConstruct 处理、@Autowired 处理
-
InitializingBean 与 init-method:
- afterPropertiesSet() 方法
- 自定义的 init 方法
-
BeanPostProcessor 后置处理:
- postProcessAfterInitialization 方法
- 典型应用:AOP 代理创建
java复制// 初始化阶段的核心代码流程
// 1. Aware 接口处理
invokeAwareMethods(beanName, bean);
// 2. BeanPostProcessor 前置处理
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 3. 初始化方法调用
invokeInitMethods(beanName, wrappedBean, mbd);
// 4. BeanPostProcessor 后置处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
1.5 销毁阶段:资源清理
当容器关闭时,会触发 Bean 的销毁流程。销毁阶段主要处理:
- @PreDestroy 注解标记的方法
- DisposableBean 接口的 destroy() 方法
- 自定义的 destroy-method
销毁回调的注册在 AbstractAutowireCapableBeanFactory.registerDisposableBeanIfNecessary() 方法中完成。Spring 会将这些回调封装成 DisposableBeanAdapter 对象并保存起来,待容器关闭时统一调用。
实际开发中,我们经常需要在销毁时释放数据库连接、关闭文件句柄等资源。正确的做法是将这些清理逻辑放在 @PreDestroy 方法中,而不是依赖 finalize() 方法。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Spring Bean 作用域深度解析
Spring 提供了多种 Bean 作用域,每种作用域都有其特定的使用场景和实现机制。理解这些作用域的区别对于设计正确的 Spring 应用至关重要。
2.1 Singleton 作用域的实现原理
Singleton 是默认的作用域,整个容器中只有一个实例。Spring 通过 ConcurrentHashMap 实现单例缓存:
java复制private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
单例 Bean 的创建流程有严格的同步控制:
- 检查一级缓存(singletonObjects)中是否存在
- 如果不存在,加锁(synchronized)
- 再次检查(双重检查锁定模式)
- 创建实例并放入缓存
单例 Bean 的线程安全问题:虽然 Spring 保证了单例 Bean 本身的创建是线程安全的,但如果 Bean 有可变状态(成员变量),开发者需要自行处理线程安全问题。
2.2 Prototype 作用域的特殊性
Prototype 作用域的 Bean 每次获取都会创建一个新实例。Spring 不会缓存这些实例,也不会管理它们的生命周期。这意味着:
- 容器不会调用 Prototype Bean 的销毁方法
- 依赖注入只发生一次(在创建时)
- 需要手动管理资源清理
java复制// Prototype Bean 的创建流程
if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
2.3 Web 相关作用域的实现机制
Request、Session、Application 等作用域是为 Web 应用设计的。它们的实现依赖于 Scope 接口:
java复制public interface Scope {
Object get(String name, ObjectFactory<?> objectFactory);
Object remove(String name);
void registerDestructionCallback(String name, Runnable callback);
// ...
}
Spring 通过 RequestContextListener 或 RequestContextFilter 将这些作用域与 HTTP 请求/会话绑定。核心实现类包括:
- RequestScope:基于 HttpServletRequest 属性
- SessionScope:基于 HttpSession 属性
- ApplicationScope:基于 ServletContext 属性
在非 Web 环境中使用这些作用域会抛出 IllegalStateException。测试时需要额外配置 Mock 环境。
2.4 自定义作用域的实践
自定义作用域需要实现 Scope 接口并注册到容器中。一个典型的使用场景是实现"线程作用域":
java复制public class ThreadScope implements Scope {
private final ThreadLocal<Map<String, Object>> threadLocal =
ThreadLocal.withInitial(HashMap::new);
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
Map<String, Object> scope = threadLocal.get();
Object obj = scope.get(name);
if (obj == null) {
obj = objectFactory.getObject();
scope.put(name, obj);
}
return obj;
}
@Override
public Object remove(String name) {
Map<String, Object> scope = threadLocal.get();
return scope.remove(name);
}
// 其他方法实现...
}
注册自定义作用域:
java复制ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerScope("thread", new ThreadScope());
使用自定义作用域:
java复制@Component
@Scope("thread")
public class ThreadScopedBean {
// ...
}
3. Spring Boot 自动配置原理剖析
Spring Boot 的自动配置是其最强大的特性之一,它通过约定优于配置的原则大幅简化了 Spring 应用的配置工作。
3.1 @EnableAutoConfiguration 的魔法
@SpringBootApplication 注解包含了 @EnableAutoConfiguration,它是自动配置的入口。其核心工作原理:
- 加载 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件
- 过滤掉被 exclude 的配置类
- 根据条件(@Conditional)决定是否应用配置
自动配置的加载顺序由 AutoConfigurationSorter 确定,它会处理 @AutoConfigureBefore、@AutoConfigureAfter 等注解。
调试自动配置的小技巧:启动时添加 --debug 参数,Spring Boot 会打印所有条件评估报告。
3.2 条件注解的运作机制
Spring Boot 提供了一系列条件注解来控制配置类的加载:
- @ConditionalOnClass:类路径下存在指定类时生效
- @ConditionalOnMissingBean:容器中不存在指定 Bean 时生效
- @ConditionalOnProperty:配置属性满足条件时生效
- @ConditionalOnWebApplication:Web 应用环境下生效
这些条件注解的核心是 Condition 接口:
java复制public interface Condition {
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
Spring 会在解析配置类时调用所有相关 Condition 的 matches 方法进行评估。
3.3 自动配置类的典型结构
一个典型的自动配置类包含以下要素:
java复制@AutoConfiguration
@ConditionalOnClass(SomeService.class)
@EnableConfigurationProperties(SomeProperties.class)
public class SomeAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public SomeService someService(SomeProperties properties) {
return new SomeService(properties.getUrl());
}
@Bean
@ConditionalOnProperty("some.feature.enabled")
public SomeFeature someFeature() {
return new SomeFeature();
}
}
这种结构体现了 Spring Boot 的默认配置哲学:
- 提供合理的默认值
- 允许用户自定义 Bean 来覆盖默认配置
- 通过外部配置控制功能开关
3.4 自动配置的调试与定制
当自动配置不符合需求时,可以通过以下方式定制:
-
排除自动配置类:
java复制@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) -
使用配置属性:
properties复制spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration -
定义自己的自动配置:
- 创建 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件
- 编写带有 @AutoConfiguration 的配置类
- 提供适当的条件注解
实际项目中,我们经常需要查看自动配置的生效情况。除了 --debug 参数外,还可以使用 Spring Boot Actuator 的 /conditions 端点。
4. 高级话题:Bean 生命周期扩展实战
Spring 提供了多种扩展点允许开发者介入 Bean 的生命周期,实现自定义逻辑。
4.1 BeanPostProcessor 的高级用法
BeanPostProcessor 是最强大的扩展点之一。常见应用场景:
-
AOP 代理创建:
java复制public abstract class AbstractAutoProxyCreator implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanName) { // 创建代理逻辑 } } -
注解处理:
java复制public class CustomAnnotationProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { // 处理自定义注解 } } -
监控与统计:
java复制public class MonitoringBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanName) { // 记录Bean初始化耗时等指标 } }
4.2 BeanFactoryPostProcessor 的应用
BeanFactoryPostProcessor 允许在 Bean 实例化前修改 BeanDefinition。典型应用:
-
属性占位符解析:
java复制public class PropertySourcesPlaceholderConfigurer implements BeanFactoryPostProcessor { public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 解析 ${...} 占位符 } } -
动态注册 Bean:
java复制public class DynamicBeanRegistrar implements BeanFactoryPostProcessor { public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { GenericBeanDefinition definition = new GenericBeanDefinition(); definition.setBeanClass(SomeClass.class); ((BeanDefinitionRegistry)beanFactory).registerBeanDefinition("dynamicBean", definition); } } -
配置验证:
java复制public class ConfigurationValidator implements BeanFactoryPostProcessor { public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 验证配置是否正确 } }
4.3 生命周期接口的综合应用案例
结合多个生命周期接口实现一个完整的扩展功能:
java复制public class AuditBeanLifecycle implements
BeanPostProcessor, InitializingBean, DisposableBean {
private final Map<String, Long> initializationTimes = new ConcurrentHashMap<>();
private final Map<String, Long> destructionTimes = new ConcurrentHashMap<>();
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
initializationTimes.put(beanName, System.currentTimeMillis());
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
long duration = System.currentTimeMillis() - initializationTimes.get(beanName);
System.out.println(beanName + " initialized in " + duration + "ms");
return bean;
}
@Override
public void afterPropertiesSet() {
System.out.println("AuditBeanLifecycle initialized");
}
@Override
public void destroy() {
System.out.println("AuditBeanLifecycle destroyed");
System.out.println("Destruction times: " + destructionTimes);
}
}
这个例子展示了如何:
- 使用 BeanPostProcessor 监控初始化时间
- 实现 InitializingBean 进行自身初始化
- 实现 DisposableBean 进行资源清理
4.4 生命周期回调的顺序总结
当多种生命周期机制同时存在时,它们的执行顺序如下:
- BeanPostProcessor.postProcessBeforeInitialization
- @PostConstruct 方法
- InitializingBean.afterPropertiesSet
- 自定义的 init-method
- BeanPostProcessor.postProcessAfterInitialization
- @PreDestroy 方法
- DisposableBean.destroy
- 自定义的 destroy-method
理解这个顺序对于处理复杂的初始化逻辑非常重要,特别是在有多个 BeanPostProcessor 相互影响的情况下。
