引言
在前面的文章中我们提到了springboot的自动包配置原理,并且深入了源码剖析,那么问题来了,spring当中bean是如何进行实例化和初始化的呢?在 Spring 框架中,Bean 的创建和管理是其核心功能之一。Spring 容器通过一系列复杂且严谨的流程,从解析配置开始,到最终完成 Bean 的初始化,整个过程涉及多个关键阶段。理解这些阶段不仅有助于我们更好地掌握 Spring 框架的工作原理,还能在实际开发中更高效地使用和调试 Spring 应用。接下来,就让我们详细进入 Spring Bean 实例化与初始化的完整流程。
详细步骤解析
1. Bean 定义解析与注册
Spring 启动时,会扫描各种配置源,这些配置源可以是 XML 文件、注解或者 Java Config。Spring 会将这些配置信息中的 Bean 定义转换为 BeanDefinition
对象,然后将其注册到 BeanDefinitionRegistry
中。
以下是一个简单的伪代码示例,展示从 @Component
注解解析 BeanDefinition
的过程:
java
// 伪代码示例:从@Component注解解析BeanDefinition
@Component
public class UserService {}
// 对应的BeanDefinition元数据
BeanDefinition bd = new RootBeanDefinition(UserService.class);
bd.setScope("singleton");
bd.setLazyInit(false);
beanFactory.registerBeanDefinition("userService", bd);
在这个示例中,UserService
类被 @Component
注解标记,Spring 会将其解析为一个 BeanDefinition
对象,并将其注册到 BeanFactory
中,指定作用域为单例,且不进行懒加载(都是可以自定义的)。
2. Bean 实例化阶段
当容器需要获取某个 Bean 时(例如首次调用 getBean()
方法),就会进入实例化流程。以下是 AbstractBeanFactory
中 getBean()
方法的核心调用链:
java
// AbstractBeanFactory#getBean() 核心调用链
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) {
// 1. 从缓存获取单例Bean(若存在)
Object sharedInstance = getSingleton(beanName);
// 2. 若不存在,则创建新实例
if (sharedInstance == null) {
// 创建Bean实例
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args);
});
}
// ... 处理其他作用域(原型、会话等)
}
return (T) getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
在这个过程中,Spring 首先会尝试从缓存中获取单例 Bean,如果缓存中不存在,则会根据 Bean 的作用域创建新的实例。主要是根据bean的定义选择实例化的方式。
3. 实例化策略选择
根据 Bean 定义,Spring 会选择合适的实例化方式,常见的有构造函数实例化和工厂方法实例化。以下是 AbstractAutowireCapableBeanFactory
中 createBeanInstance()
方法的实现:
java
// AbstractAutowireCapableBeanFactory#createBeanInstance()
protected Object createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 1. 解析构造函数(如有参数或@Autowired构造函数)
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR) {
return autowireConstructor(beanName, mbd, ctors, args); // 有参构造函数注入
}
// 2. 使用默认无参构造函数(最常见情况)
return instantiateBean(beanName, mbd);
}
// 默认无参构造函数实例化
protected Object instantiateBean(String beanName, RootBeanDefinition mbd) {
BeanInstantiationStrategy strategy = getInstantiationStrategy();
return strategy.instantiate(mbd, beanName, this); // 通过策略模式选择实例化方式
}
Spring 会优先检查是否存在有参构造函数或者被 @Autowired
注解标记的构造函数,如果存在则使用有参构造函数进行实例化;否则,会使用默认的无参构造函数进行实例化。
4. Aware 接口回调处理
实例化完成后,Spring 会通过 ApplicationContextAwareProcessor
处理各种 Aware
接口。Aware
接口允许 Bean 获取 Spring 容器的一些信息,例如 Bean 的名称、类加载器、Bean 工厂等。
java
// ApplicationContextAwareProcessor#postProcessBeforeInitialization()
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
// 处理ApplicationContext相关Aware接口
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(applicationContext.getEnvironment());
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(applicationContext);
}
// ... 其他Aware接口
return bean;
}
通过实现这些 Aware
接口,Bean 可以在初始化过程中获取到 Spring 容器的相关信息,从而实现更灵活的功能。
设计意图 : 让 Bean 在初始化阶段就能获取容器信息,避免硬编码依赖(如直接通过 ApplicationContext.getBean()
获取其他 Bean)。 遵循依赖注入原则,将容器资源通过接口注入给 Bean。
5. BeanPostProcessor 前置处理
在初始化前,Spring 会应用所有 BeanPostProcessor
的前置处理逻辑。BeanPostProcessor
是 Spring 提供的一个扩展点,允许开发者在 Bean 初始化前后进行自定义的处理。这是 AOP、依赖检查等功能的核心扩展点。
java
// AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization()
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
在这个过程中,每个 BeanPostProcessor
都会对 Bean 进行处理,开发者可以通过实现 BeanPostProcessor
接口来添加自定义的逻辑。
-
与 Aware 接口的区别:
- Aware 接口 :由特定处理器(如
ApplicationContextAwareProcessor
)处理,仅针对实现特定接口的 Bean。 - BeanPostProcessor:全局处理器,对所有 Bean 生效(除非显式排除)。
- Aware 接口 :由特定处理器(如
6. 初始化方法调用
Spring 支持三种初始化回调方式,按执行顺序依次为:
- @PostConstruct 注解(JSR-250 规范)
- InitializingBean 接口(Spring 内置)
- 自定义初始化方法 (XML 配置或
@Bean(initMethod=...)
)
Spring 会触发 InitializingBean
接口或自定义初始化方法。InitializingBean
接口提供了一个 afterPropertiesSet()
方法,在 Bean 的属性设置完成后会被调用。同时,也可以使用 @PostConstruct
注解或在 XML 配置中指定 init-method
属性来定义自定义的初始化方法。
java
// AbstractAutowireCapableBeanFactory#invokeInitMethods()
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
// 1. 处理InitializingBean接口
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
((InitializingBean) bean).afterPropertiesSet();
}
// 2. 处理自定义初始化方法(@PostConstruct或init-method属性)
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
通过这些初始化方法,可以在 Bean 初始化完成后执行一些必要的操作。
7. BeanPostProcessor 后置处理
在初始化后,Spring 会应用所有 BeanPostProcessor
的后置处理逻辑,其中一个典型的应用就是 AOP 代理。这是 AOP 代理最终生成的关键阶段。
java
// AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization()
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
关键细节与理解
-
AOP 代理生成时机:
- Spring AOP 的默认实现(如
AnnotationAwareAspectJAutoProxyCreator
)在此阶段通过 CGLIB 或 JDK 动态代理生成代理对象。 - 代理对象会替换原始 Bean 实例,后续容器返回的都是代理对象。
- Spring AOP 的默认实现(如
在这个阶段,BeanPostProcessor
可以对 Bean 进行进一步的处理,例如为 Bean 创建代理对象。
流程图总结
plaintext
配置解析 → BeanDefinition注册 → 获取Bean → 实例化(构造函数/工厂方法)
→ Aware接口回调(BeanNameAware/BeanFactoryAware等)
→ BeanPostProcessor前置处理
→ 初始化方法调用(InitializingBean/@PostConstruct)
→ BeanPostProcessor后置处理(如AOP代理)
→ Bean就绪
总结
Spring Bean 的实例化与初始化是一个复杂而有序的过程,涉及多个关键阶段和扩展点。通过深入理解这些流程通过深入理解这些阶段和扩展点,我们可以更精准地定位问题,同时利用 Spring 的扩展性实现复杂的业务需求。