SmartInstantiationAwareBeanPostProcessor 专用于构造器选择与早期引用暴露,不适用于初始化逻辑或AOP代理;其方法仅在三级缓存触发循环依赖时调用,且必须在BeanDefinition加载完成前注册。

SmartInstantiationAwareBeanPostProcessor 的真实作用边界
它不是用来“深度干预”整个生命周期的万能钩子,而是专门解决构造器选择和早期引用暴露这两个具体问题。如果你的目标是改初始化逻辑、加 AOP 代理或拦截属性注入,SmartInstantiationAwareBeanPostProcessor 不是第一选择——InstantiationAwareBeanPostProcessor 或 BeanPostProcessor 更对口。
它的核心价值在于:Spring 在实例化前需要决定「用哪个构造函数」,以及「是否允许其他 Bean 提前拿到这个尚未初始化完成的对象(比如解决循环依赖)」。这两个动作都发生在 postProcessBeforeInstantiation 之后、真正调用 constructor 之前。
为什么 getEarlyBeanReference 会被忽略?
很多开发者写了 getEarlyBeanReference 却发现没生效,根本原因是:这个方法只在 Spring 判定当前 Bean 可能被其他 Bean 循环引用时才触发。它不是每次创建都调用,而是由三级缓存机制驱动的「按需调用」。
- 如果 Bean 是
prototype作用域,不会进三级缓存 →getEarlyBeanReference永远不执行 - 如果当前 Bean 没有被任何其他正在创建中的 Bean 引用 → 不触发
- 如果 Bean 已经被标记为
isSingletonCurrentlyInCreation但你没在getEarlyBeanReference返回非 null 对象 → Spring 会 fallback 到原始 bean 实例,你的包装逻辑就丢了
典型写法:
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
return Proxy.newProxyInstance(
bean.getClass().getClassLoader(),
bean.getClass().getInterfaces(),
(proxy, method, args) -> {
System.out.println("early call: " + method.getName());
return method.invoke(bean, args);
}
);
}
return bean;
}
predictBeanType 和 determineCandidateConstructors 怎么配合用?
这两个方法共同决定了「Spring 最终调用哪个构造器」。单独改其中一个,往往达不到预期效果。
predictBeanType 告诉容器:“这个 Bean 名字虽然叫 X,但实际类型我建议你当成 Y 处理”,影响后续类型匹配逻辑;determineCandidateConstructors 则直接返回一组候选构造器数组,Spring 会从中挑一个最匹配的(比如参数最多、类型最具体的那个)。
- 如果你返回空数组(
null),Spring 会退回到默认策略:找无参构造器 - 如果你返回带参数的构造器,但参数类型在容器中找不到匹配的 Bean → 启动失败,报
NoUniqueBeanDefinitionException或UnsatisfiedDependencyException - 不要在
determineCandidateConstructors里做耗时操作,它在 refresh 阶段被高频调用,会影响启动速度
常见误用:想用它实现「根据 profile 动态选构造器」,结果 profile 还没加载完,BeanFactory 就开始解析构造器了 —— 此时应优先考虑 @Profile + 多个 @Bean 方法,而不是在这里硬塞逻辑。
和 InstantiationAwareBeanPostProcessor 的关键差异点
别把 SmartInstantiationAwareBeanPostProcessor 当成增强版的 InstantiationAwareBeanPostProcessor。它们职责不同,且调用顺序严格固定:
-
postProcessBeforeInstantiation(父接口)→determineCandidateConstructors→predictBeanType→getEarlyBeanReference - 也就是说,你无法在
getEarlyBeanReference里修改构造器选择,也无法在determineCandidateConstructors里提前返回代理对象 -
postProcessAfterInstantiation和postProcessProperties在Smart接口中被继承,但它们的语义和父接口完全一致,没有额外行为
最容易被忽略的一点:SmartInstantiationAwareBeanPostProcessor 的所有方法都必须在 BeanDefinition 加载完成、但任何实例还没创建前就注册进容器。如果通过 @Bean 方式声明它,必须确保其 @Bean 方法在所有其他 Bean 定义解析之前执行 —— 否则部分 Bean 可能跳过你的逻辑。










