在阅读refresh#finishBeanFactoryInitialization方法时我看到了一段代码:
// Call BeanFactoryInitializer beans early to allow for initializing specific other beans early.
// Spring6.2新特性
String[] initializerNames = beanFactory.getBeanNamesForType(BeanFactoryInitializer.class, false, false);
for (String initializerName : initializerNames) {
beanFactory.getBean(initializerName, BeanFactoryInitializer.class).initialize(beanFactory);
}BeanFactory初始化器,在refresh#finishBeanFactoryInitialization中调用,是Spring6.2后一个针对于BeanFactory的扩展点。
/**
* Callback interface for initializing a Spring {@link ListableBeanFactory}
* prior to entering the singleton pre-instantiation phase. Can be used to
* trigger early initialization of specific beans before regular singletons.
*
* <p>Can be programmatically applied to a {@code ListableBeanFactory} instance.
* In an {@code ApplicationContext}, beans of type {@code BeanFactoryInitializer}
* will be autodetected and automatically applied to the underlying bean factory.
*
* @author Juergen Hoeller
* @since 6.2
* @param <F> the bean factory type
* @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons()
*/
public interface BeanFactoryInitializer<F extends ListableBeanFactory> {
/**
* Initialize the given bean factory.
* @param beanFactory the bean factory to bootstrap
*/
void initialize(F beanFactory);
}注释的意思:
在进入单例预实例化阶段之前,用于初始化 Spring
ListableBeanFactory的回调接口。可用于在常规单例 Bean 之前,触发特定 Bean 的提前初始化。
可以编程方式应用于
ListableBeanFactory实例。在
ApplicationContext中,类型为BeanFactoryInitializer的 Bean 会被自动检测,并自动应用于底层的 BeanFactory。
具体用法:
@Component
public class MyBeanFactoryInitializer implements BeanFactoryInitializer<DefaultListableBeanFactory> {
@Override
public void initialize(DefaultListableBeanFactory beanFactory) {
// 在这里可以让某些Bean的创建过程提前
beanFactory.getBean("userService");
}
}@Component
@Lazy
public class UserService {
@PostConstruct
public void test() {
System.out.println("test...");
}
}public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(MyConfig.class);
applicationContext.refresh();
}
}UserService是非懒加载的单例Bean,我们也可以在容器启动完成后就自动触发它的初始化。
思考:
1、BeanFactoryInitializer 也可以修改 BeanDefinition。DefaultListableBeanFactory它继承了ConfigurableListableBeanFactory,因此也可以获取BeanDefinition然后调用setXxx,还可以注册和移除BeanDefinition。个人觉得在这里修改BeanDefinition反而更加确定,因为执行时机是在非懒加载单例Bean实例化之前。但是官方并不推荐,而且有点故意隐藏的操作BeanDefinition的API的意思,BeanFactoryInitializer的泛型必须是ListableBeanFactory类型,看看ListableBeanFactory的实现就知道了。
2、后面还会学习BeanFactoryPostProcessor接口,这个接口里是强烈不建议实例化Bean的,它可能打乱Bean的生命周期,因为BeanPostProcessor还没有注册。BeanFactoryPostProcessor执行时机是还没有任何单例 Bean 被实例化,但BeanFactoryInitializer执行时,有一些内部基础设施 Bean已经实例化了。
官方文档:BeanFactoryPostProcessor 中不应该尝试实例化 Bean,否则会过早触发 Bean 的实例化,导致 BeanPostProcessor 无法正常生效。
3、总之,BeanFactoryInitializer主要作用就是可用于在常规单例 Bean 之前,触发特定 Bean 的提前初始化。
总结:用哪个?
结论: BeanFactoryInitializer 不是重复的发明,而是一个职责分离、时机正确、性能更优、更安全的专门化扩展点。它让“我想配置工厂”这个需求的代码比用笨重的BeanFactoryPostProcessor来写更加优雅、清晰和健壮。这是Spring框架持续优化其内部可扩展性架构的一个体现。