Skip to content
Go back

Spring IoC容器——BeanDefinition到Bean实例的完整旅程

Spring IoC 容器:Bean 是怎么被创建出来的?

一句话结论(30s)

Spring IoC 的本质是「先登记再生产」——扫描配置先生成 BeanDefinition 元数据,再按它反射实例化并注入依赖。其关键设计是阶段分离BeanFactoryPostProcessor 在实例化前改元数据(配方层),BeanPostProcessor 在实例化后处理实例对象(烹饪层),AOP 代理统一在 postProcessAfterInitialization 阶段生成。之所以能无限扩展 @Autowired@Transactional@Async 这些能力,是因为它们都只是不同的 BPP 实现,各自独立互不干扰。

思考:为什么 Spring 要「先登记再生产」,而不是拿到配置直接 new 出来?

因为「登记」这一步把 Bean 变成了一张统一的「配方」(BeanDefinition),后面的所有扩展才能在同一套流程里展开——无论配置来自 XML、注解还是 Java Config,最终都收敛成元数据,后置处理器也才能在实例化前先改「配方」。如果直接 new,就没有留给扩展点的余地了。

核心原理(2min)

主流程分三步:① 解析 XML/注解/Java Config 生成 BeanDefinition 集合并注册到 BeanDefinitionRegistry;② BeanFactoryPostProcessor 介入修改 BeanDefinition(如 PropertySourcesPlaceholderConfigurer 解析 ${} 占位符);③ 对每个非懒加载单例依次执行 createBeanInstance(反射 new 原始对象)→ populateBean@Autowired/@Value 注入)→ postProcessBeforeInitialization(处理 @PostConstruct)→ afterPropertiesSet/init-method → postProcessAfterInitialization(生成 AOP 代理)。关键机制是 before/after 分阶段:before 作用在原始对象上,after 在完整就绪的成品上生成代理,两者互不干扰;循环依赖时则通过三级缓存的 getEarlyBeanReference() 提前生成代理,after 阶段检测到已提前代理则跳过。

底层深入(5-10min)

容器启动流程

1. 解析配置(XML/注解/Java Config)
   → 生成 BeanDefinition 集合
   → 注册到 BeanDefinitionRegistry

2. BeanFactoryPostProcessor 介入 ← 可修改 BeanDefinition(元数据层)
   → 如 PropertySourcesPlaceholderConfigurer 解析 ${} 占位符

3. 实例化所有非懒加载单例 Bean:
   a. createBeanInstance (反射 new 原始对象)
   b. populateBean (依赖注入 @Autowired/@Value)
   c. BeanPostProcessor.postProcessBeforeInitialization ← @PostConstruct 处理
   d. afterPropertiesSet / init-method
   e. BeanPostProcessor.postProcessAfterInitialization  ← AOP 代理生成

源码逐段解析:Bean 生命周期的各阶段

上面这张流程图里的每一步,在 Spring 源码里都有对应的真实实现。下面按调用顺序逐段拆开,所有代码均摘自 AbstractAutowireCapableBeanFactoryDefaultListableBeanFactory(Spring 6.1)。

思考:Bean 生命周期为什么要拆成这么多阶段,一个 new + 几个 set 不就完事了?

因为每一个阶段都是一个扩展点。拆得越细,你越能在不修改核心代码的前提下插入自己的逻辑:元数据阶段给 BFPP 改配方,实例化阶段给构造器策略切换,注入阶段给 @Autowired,初始化前后给 @PostConstruct 和 AOP。阶段即钩子,钩子越多,框架越灵活。

入口:getBean → resolveBean(DefaultListableBeanFactory)

public <T> T getBean(Class<T> requiredType, @Nullable Object @Nullable ... args) throws BeansException {
    Assert.notNull(requiredType, "Required type must not be null");
    Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
    if (resolved == null) {
        throw new NoSuchBeanDefinitionException(requiredType);
    }
    return (T) resolved;
}

private <T> @Nullable T resolveBean(ResolvableType requiredType, @Nullable Object @Nullable [] args, boolean nonUniqueAsNull) {
    NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
    if (namedBean != null) {
        return namedBean.getBeanInstance();
    }
    BeanFactory parent = getParentBeanFactory();
    if (parent instanceof DefaultListableBeanFactory dlbf) {
        return dlbf.resolveBean(requiredType, args, nonUniqueAsNull);
    }
    else if (parent != null) {
        ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
        if (args != null) {
            return parentProvider.getObject(args);
        }
        else {
            return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
        }
    }
    return null;
}

按类型取 Bean 时,getBean 把类型包装成 ResolvableType 后交给 resolveBeanresolveBean 先调用 resolveNamedBean 按类型匹配出候选 beanName 再逐个实例化,找不到就向上委托给父容器。这里只是”取用入口”,真正创建 Bean 的逻辑并不在这一层,而是藏在父类 AbstractBeanFactory#doGetBean 里,最终回调到 createBeandoCreateBean

主流程:doCreateBean(三段式总调度)

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object @Nullable [] args)
        throws BeanCreationException {

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    // Allow post-processors to modify the merged bean definition.
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Post-processing of merged bean definition failed", ex);
            }
            mbd.markAsPostProcessed();
        }
    }

    // Eagerly cache singletons to be able to resolve circular references
    // even when triggered by lifecycle interfaces like BeanFactoryAware.
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isTraceEnabled()) {
            logger.trace("Eagerly caching bean '" + beanName +
                    "' to allow for resolving potential circular references");
        }
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        populateBean(beanName, mbd, instanceWrapper);
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
        if (ex instanceof BeanCreationException bce && beanName.equals(bce.getBeanName())) {
            throw bce;
        }
        throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
    }

    // ...
    return exposedObject;
}

doCreateBean 是 Bean 生命周期真正的总调度器,核心只有三行:createBeanInstancepopulateBeaninitializeBean。中间的 addSingletonFactory 是三级缓存解决循环依赖的关键——它在 populate 之前就把”早期引用工厂”放进三级缓存,让依赖它的 B 能先拿到 A 的早期引用,等 A 完整后再用 earlySingletonReference 替换回来。

思考:循环依赖为什么非要在 populate 之前把「早期引用工厂」塞进三级缓存?

因为循环依赖的根源是「A 依赖 B、B 又依赖 A」,如果 A 必须完全创建好才暴露,B 拿不到 A 就永远卡死。Spring 的解法是「先把半成品交出去」:populate 之前,A 虽然还没注入、没初始化,但引用是确定的了,提前把「能造出 A 早期引用的工厂」放进缓存,B 就能先引用它,等 A 完整后再用 earlySingletonReference 换回成品。

阶段一:createBeanInstance(反射 new 出原始对象)

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object @Nullable [] args) {
    // Make sure bean class is actually resolved at this point.
    Class<?> beanClass = resolveBeanClass(mbd, beanName);

    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
    }

    if (args == null) {
        Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
        if (instanceSupplier != null) {
            return obtainFromSupplier(instanceSupplier, beanName, mbd);
        }
    }

    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // Shortcut when re-creating the same bean...
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    if (resolved) {
        if (autowireNecessary) {
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            return instantiateBean(beanName, mbd);
        }
    }

    // Candidate constructors for autowiring?
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // Preferred constructors for default construction?
    ctors = mbd.getPreferredConstructors();
    if (ctors != null) {
        return autowireConstructor(beanName, mbd, ctors, null);
    }

    // No special handling: simply use no-arg constructor.
    return instantiateBean(beanName, mbd);
}

createBeanInstance 只做一件事——拿到”原始对象”,绝不注入依赖。它按优先级挑选构造方式:Supplier 回调 > 工厂方法 > 已缓存的构造器 > @Autowired 构造器(determineConstructorsFromBeanPostProcessors)> 默认无参构造。注意 @Autowired 字段注入在这里还没发生,要等到 populateBean 阶段。

思考:为什么不直接 new 出对象的同时把依赖一起注入,非要拆成「实例化」和「注入」两步?

因为构造对象的方式不止一种——可能是 Supplier 回调、工厂方法、@Autowired 构造器或默认无参构造,每种都需要独立决策;而注入又分构造器、字段、Setter 三种。混在一起,任何一处扩展都要动核心代码。拆开后,「怎么造」和「怎么填」各自独立,也让循环依赖的提前暴露有了可插手的时机。

阶段二:populateBean(依赖注入)

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    if (bw == null) {
        if (mbd.hasPropertyValues()) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
        }
        else {
            // Skip property population phase for null instance.
            return;
        }
    }

    if (bw.getWrappedClass().isRecord()) {
        if (mbd.hasPropertyValues()) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Cannot apply property values to a record");
        }
        else {
            // Skip property population phase for records since they are immutable.
            return;
        }
    }

    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    // state of the bean before properties are set. This can be used, for example,
    // to support styles of field injection.
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
            if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                return;
            }
        }
    }

    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // Add property values based on autowire by name if applicable.
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // Add property values based on autowire by type if applicable.
        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }
    if (hasInstantiationAwareBeanPostProcessors()) {
        if (pvs == null) {
            pvs = mbd.getPropertyValues();
        }
        for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
            PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
                return;
            }
            pvs = pvsToUse;
        }
    }

    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    if (needsDepCheck) {
        PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        checkDependencies(beanName, mbd, filteredPds, pvs);
    }

    if (pvs != null) {
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

populateBean 负责把所有依赖灌进原始对象。@Autowired/@Value 的字段注入就发生在 InstantiationAwareBeanPostProcessor#postProcessProperties 这一环(由 AutowiredAnnotationBeanPostProcessor 实现)。postProcessAfterInstantiation 返回 false 可以直接短路后续属性填充;pvs 一路被各后置处理器改写,最后由 applyPropertyValues 真正通过 setter 或反射写入字段。

思考:注入这种「核心动作」,为什么要交给 InstantiationAwareBeanPostProcessor 这种可插拔的扩展,而不是在 populateBean 里写死?

因为注解是会「长」的。今天有 @Autowired@Value@Resource,明天你可能自定义一个 @MyInject。把注入抽象成后置处理器后,新增注入注解只需再注册一个实现,populateBean 主流程一行都不用改——这就是开闭原则在框架里的落地。

阶段三:initializeBean(初始化编排)

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    // Skip initialization of a NullBean
    if (bean.getClass() == NullBean.class) {
        return bean;
    }

    invokeAwareMethods(beanName, bean);

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

initializeBean 是初始化阶段的编排者,执行顺序严格固定:Aware 回调 → before 后置处理 → init-method → after 后置处理。@PostConstruct 对应的 InitDestroyAnnotationBeanPostProcessor 挂在 before 阶段,AOP 代理(AbstractAutoProxyCreator)挂在 after 阶段。mbd.isSynthetic() 判断用于跳过 AOP 基础设施自身 Bean 的处理,避免无限递归。

Aware 回调:invokeAwareMethods

private void invokeAwareMethods(String beanName, Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware beanNameAware) {
            beanNameAware.setBeanName(beanName);
        }
        if (bean instanceof BeanClassLoaderAware beanClassLoaderAware) {
            ClassLoader bcl = getBeanClassLoader();
            if (bcl != null) {
                beanClassLoaderAware.setBeanClassLoader(bcl);
            }
        }
        if (bean instanceof BeanFactoryAware beanFactoryAware) {
            beanFactoryAware.setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

Aware 系列接口让 Bean 能感知容器自身的元信息(名字、类加载器、工厂)。这里只硬编码了三个 Aware;ApplicationContextAwareEnvironmentAware 等其余 Aware 由 ApplicationContextAwareProcessor 这个 BPP 在 before 阶段注入。这正是”不用 @Autowired 也能拿到容器对象”的底层机制。

初始化方法:invokeInitMethods

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
        throws Throwable {

    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isTraceEnabled()) {
            logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        ((InitializingBean) bean).afterPropertiesSet();
    }

    if (mbd != null && bean.getClass() != NullBean.class) {
        String[] initMethodNames = mbd.getInitMethodNames();
        if (initMethodNames != null) {
            for (String initMethodName : initMethodNames) {
                if (StringUtils.hasLength(initMethodName) &&
                        !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                        !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
                    invokeCustomInitMethod(beanName, bean, mbd, initMethodName);
                }
            }
        }
    }
}

init 阶段有两个入口:实现 InitializingBean 接口的 afterPropertiesSet(),以及 BeanDefinition 里声明的 init-method。它们按”先接口、后配置”的顺序执行,并通过 hasAnyExternallyManagedInitMethod 去重,避免 @Bean(initMethod=...) 与接口回调重复触发。

BeanPostProcessor 链:before / after

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;
}

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;
}

BPP 链本质上是一个有序的 for 循环,前一个处理器的返回值作为下一个的输入,构成”责任链”。任何一个处理器返回 null 都会短路——直接返回当前结果,不再走后续处理器。这就是为什么 BPP 必须按 PriorityOrdered/Ordered 排序注册:顺序不同,行为就可能不同(例如多个代理创建器同时存在时只有排前面的生效)。

思考beforeafter 两个阶段看起来对称,为什么不合并成一个?

因为它们作用的对象状态不同。before 面对的是「依赖已注入、但 @PostConstruct/init-method 还没跑」的半成品,after 面对的是「一切就绪」的成品。AOP 代理必须放在 after——如果放在 before,代理会先包裹半成品,等 init 方法执行时 this 指向的是代理而非目标,行为会错乱。阶段分离的本质是「状态分离」。

BeanDefinition:描述”这个 Bean 应该怎么创建”

BeanDefinition 是一张”食谱”,Bean 工厂根据它来烹饪 Bean。包含:

beanClassName:   全限定类名
scope:           singleton / prototype / request / session
lazyInit:        是否懒加载
dependsOn:       依赖的其他 Bean
initMethodName:  初始化方法名
destroyMethodName: 销毁方法名
propertyValues:  属性注入列表

Spring 扫描到 @Component@Service 注解后,生成对应的 BeanDefinition 存入注册表。此时 Bean 还没有被实例化——注册表只是一个”待办清单”。

BeanPostProcessor vs BeanFactoryPostProcessor

这是两个最容易被混淆的概念,但它们的区别非常清晰:

BeanFactoryPostProcessorBeanPostProcessor
作用对象BeanDefinition(元数据)Bean 实例(对象)
执行时机Bean 实例化之前Bean 实例化之后
典型实现PropertySourcesPlaceholderConfigurerAutowiredAnnotationBeanPostProcessor
能力修改 class、scope、属性值等元数据修改/替换/代理 Bean 实例

BFPP 在食谱层面改配方,BPP 在烹饪过程中调味料。

AOP 代理为什么在 postProcessAfterInitialization?

在 after 阶段生成代理有三个好处:

  1. 目标 Bean 已完整就绪:所有依赖已注入、init-method 已执行——包裹的是”成品”
  2. before/after 分阶段:before 处理 @PostConstruct(发生在原始对象上),after 生成代理(生成在代理对象上),两者不会互相干扰
  3. 循环依赖例外:需要提前暴露引用时,getEarlyBeanReference() 在三级缓存阶段提前生成代理,after 阶段检测到已有早期代理则跳过

三种注入方式

// 1. 构造器注入(推荐)
@Service
public class OrderService {
    private final UserService userService;
    public OrderService(UserService userService) {
        this.userService = userService;
    }
}
// 优势: 不可变 (final)、必填依赖明确、易于单元测试

// 2. Setter 注入(可选依赖)
@Autowired(required = false)
public void setCache(Cache cache) { ... }

// 3. 字段注入(不推荐,但最常见)
@Autowired
private UserService userService;
// 劣势: 不利于测试、隐藏了依赖、不能声明为 final

构造器注入不依赖 @Autowired(Spring 4.3+ 单构造器自动注入),且字段可以声明为 final 保证不可变。

@ConditionalOnMissingBean 的坑

@ConditionalOnMissingBean 判断”容器中是否已有指定类型的 Bean”时,既查已实例化的 Bean(缓存)又查已注册但未实例化的 BeanDefinition。但它按配置类的处理顺序判断——如果用户的自定义 Bean 所在配置类在自动配置类之后才被处理,自动配置类判断时”没看到”用户的 Bean,条件满足,自动配置的 Bean 被注册。然后用户 Bean 也被注册 → 同类型两个 Bean 并存 → NoUniqueBeanDefinitionException

解法:@AutoConfigureBefore/@AutoConfigureAfter 明确顺序,或用户配置类上加 @Primary

总结

Spring IoC 的精妙之处在于阶段分离

这种设计让 Spring 可以在不修改核心代码的前提下无限扩展——@Autowired@Transactional@Async 都只是不同的 BPP 实现,各自独立,互不干扰。

章末提问

1. BeanFactory 和 ApplicationContext 有什么区别?

结论先行ApplicationContextBeanFactory 的超集,Spring 应用里几乎都用它。

因为BeanFactory 只提供最基础的容器能力(getBean、依赖注入),延迟到真正 getBean 时才实例化;而 ApplicationContext 在启动时就预实例化所有非懒加载单例,并额外内置了事件发布(ApplicationEvent)、国际化(MessageSource)、资源加载(ResourceLoader)、AOP 等企业级能力。进一步可答:BeanFactory 更轻、内存占用更低,适合资源受限环境;ApplicationContext 更重但功能全,是默认选择。

2. Spring 是怎么解决循环依赖的?为什么要三级缓存而不是两级?

结论先行:靠三级缓存提前暴露「早期引用」解决单例 Setter/字段注入的循环依赖,三级是为了区分「成品」和「半成品/早期代理」。

因为:一级缓存存成品,二级缓存存早期引用,三级缓存存「能造出早期引用的 ObjectFactory」。需要三级的原因有两个:一是 getEarlyBeanReference 可能生成代理,要提前把代理缓存起来避免重复生成;二是二级缓存保证了早期引用是「同一个」对象,避免循环依赖时拿到多个不一致的半成品。注意:构造器注入的循环依赖无解,因为它要求在实例化前就拿依赖,连半成品都拿不出来。

3. BeanPostProcessor 和 BeanFactoryPostProcessor 能合并成一个吗?

结论先行:不能,它们的「作用对象」和「执行时机」本质不同。

因为:BFPP 在实例化前操作 BeanDefinition(元数据),可以改 class、scope、属性值,影响的是「怎么造」;BPP 在实例化后操作 Bean 实例,可以修改、替换甚至代理对象,影响的是「造出来的东西」。合并成一个会导致时机错乱——比如占位符 ${} 必须在实例化前解析,而 @Autowired 必须在实例化后注入,二者硬塞进一个阶段只会互相干扰。

4. @Transactional、@Async 是怎么生效的?跟 BeanPostProcessor 有什么关系?

结论先行:它们本质都是「BPP + AOP 代理」,被封装成了对应的 BeanPostProcessor 实现。

因为@TransactionalInfrastructureAdvisorAutoProxyCreator(一个 BPP)在 postProcessAfterInitialization 阶段为标注了事务的方法生成代理,代理里织入事务切面;@Async 同理由 AsyncAnnotationBeanPostProcessor 生成代理。这就是「可无限扩展」的由来——每个注解能力只是一个独立的 BPP,互不干扰,Spring 核心代码从未为它们写死分支。

5. 为什么推荐构造器注入而不是字段注入?

结论先行:构造器注入让依赖「不可变、必填明确、易测试」,字段注入虽然省事但有硬伤。

因为:构造器注入可以用 final 字段,杜绝运行期被篡改,依赖在编译期就要求提供;而字段注入靠反射,隐藏了依赖关系(一眼看不出这个类依赖谁),无法 final,单元测试必须借助容器或反射 mock,还容易造成循环依赖。Spring 官方推荐构造器注入、Setter 注入用于可选依赖,字段注入「能不用就不用」。


Share this post on:

Previous Post
Spring循环依赖——三级缓存的精妙设计
Next Post
Spring AOP——JDK动态代理和CGLIB的核心区别