环境:Spring6.2.0-SNAPSHOT
1. 简介
在最新的Spring6.2.0-SNAPSHOT版本中,一项引人注目的新功能被引入——Parallel Bean Initialization during Startup,即启动过程中的并行Bean初始化。此功能旨在显著提升Spring应用程序的启动速度,为开发者带来更为流畅的开发体验。
在传统的Spring应用程序中,Bean的初始化通常是按照特定的顺序进行的,这在一定程度上限制了启动过程的并行性,影响了启动速度。然而,在Spring6.2.0-SNAPSHOT版本中,通过引入并行Bean初始化功能,Spring框架能够同时初始化多个Bean,从而显著减少启动时间。
此项功能实现基于精心设计的并发控制机制,确保Bean之间的依赖关系得到正确维护,同时最大限度地提高并行度。这意味着,即使存在复杂的Bean依赖关系,Spring也能够有效地管理并行初始化过程,避免潜在的初始化冲突或错误。
2. 实战案例
2.1 环境准备
static class PersonService {public PersonService() {try {TimeUnit.SECONDS.sleep(3) ;} catch (InterruptedException e) {}System.out.println("PersonService init ...") ;}}static class CommonService {public CommonService() {try {TimeUnit.SECONDS.sleep(3) ;} catch (InterruptedException e) {}System.out.println("CommonService init ...") ;}}
在上面的两个Service的构造方法中,分别模拟了耗时的操作。
static class AppConfig {public PersonService personService() {return new PersonService() ;}public CommonService commonService() {return new CommonService() ;}}
2.2 传统Bean初始化
StopWatch watch = new StopWatch("初始化容器") ;watch.start() ;try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class)) {}watch.stop();System.out.println(watch.prettyPrint()) ;
输出结果
PersonService init ...CommonService init ...StopWatch '初始化容器': 6.3145531 seconds----------------------------------------Seconds % Task name----------------------------------------100%
整体耗时:6.3s。
2.3 并发Bean初始化
这里首先需要修改@Bean定义配置
// 设置Bean的初始化在后台运行(bootstrap = Bootstrap.BACKGROUND)public PersonService personService() {return new PersonService() ;}(bootstrap = Bootstrap.BACKGROUND)public CommonService commonService() {return new CommonService() ;}
接着测试,输出结果

日志提示:Bean "commonService"标记为后台初始化,但未配置引导执行器-回退到主线初始化。根据提示我们还需要配置一个Executor类型的Bean。
public Executor bootstrapExecutor() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();taskExecutor.setCorePoolSize(5) ;taskExecutor.setMaxPoolSize(5) ;taskExecutor.initialize() ;return taskExecutor ;}
接着测试,输出结果
CommonService init ...PersonService init ...StopWatch '初始化容器': 3.3203919 seconds----------------------------------------Seconds % Task name----------------------------------------100%
整体耗时:3.3s,说明我们Bean的初始化分别在不同的线程中执行。
这样一来,如果你项目中如果有很多比较耗时的操作,那么通过异步线程的方式,那将节省很多的时间。
注意:上面的示例是通过注解的方式定义bean,如果你使用BeanDefinition方式定义,那么你需要做如下配置
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {context.register(AppConfig.class) ;context.registerBean(PersonDAO.class, bd -> {if (bd instanceof AnnotatedGenericBeanDefinition bean) {bean.setBackgroundInit(true) ;}}) ;context.refresh() ;}
以上是关于Spring6.2中如何配置Bean的并行处理。
3. 实现原理
Spring容器启动和兴方法refresh。
public abstract class AbstractApplicationContext {public void refresh() {finishBeanFactoryInitialization(beanFactory);}protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// 初始化bootstrap executor// 判断容器是否存在bootstrapExecutor为名的Bean,并且类型是Executorif (beanFactory.containsBean(BOOTSTRAP_EXECUTOR_BEAN_NAME) &&beanFactory.isTypeMatch(BOOTSTRAP_EXECUTOR_BEAN_NAME, Executor.class)) {// 设置到当前的BeanFactory中,后面实例化时使用beanFactory.setBootstrapExecutor(beanFactory.getBean(BOOTSTRAP_EXECUTOR_BEAN_NAME, Executor.class));}// ...// 实例化非延迟初始化单例BeanbeanFactory.preInstantiateSingletons();}}
实例化单例Bean
public class DefaultListableBeanFactory {public void preInstantiateSingletons() {List<CompletableFuture<?>> futures = new ArrayList<>();for (String beanName : beanNames) {RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);if (!mbd.isAbstract() && mbd.isSingleton()) {// 实例化BeanCompletableFuture<?> future = preInstantiateSingleton(beanName, mbd);if (future != null) {futures.add(future);}}}// 等待所有的bean都完成CompletableFuture.allOf(futures.toArray(new CompletableFuture<?>[0])).join();}private CompletableFuture<?> preInstantiateSingleton(String beanName, RootBeanDefinition mbd) {// 是否支持后台运行if (mbd.isBackgroundInit()) {Executor executor = getBootstrapExecutor();if (executor != null) {String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dep : dependsOn) {getBean(dep);}}CompletableFuture<?> future = CompletableFuture.runAsync(() -> instantiateSingletonInBackgroundThread(beanName), executor);addSingletonFactory(beanName, () -> {try {future.join();}return future;});return (!mbd.isLazyInit() ? future : null);}}// 回退到main线程执行if (!mbd.isLazyInit()) {instantiateSingleton(beanName);}return null;}}
整体的处理方式还是比较简单的。
以上是本篇文章的全部内容,如对你有帮助就请作者吃个棒棒糖🍭
完毕!!!



