How Spring 6.2 Eliminates Bean Initialization Blocking and Boosts Startup Speed
Spring 6.2 introduces asynchronous bean initialization, a new addSingletonCallback mechanism, global transaction rollback settings, and injection performance optimizations, eliminating blocking during multi‑threaded event publishing and dramatically reducing startup time, as demonstrated with code examples and performance test results.
1. Multi‑threaded Event Publishing
In Spring versions prior to 6.2, publishing an event from a bean constructor while the main thread waits for the event to complete causes the application to block. The following example reproduces the issue:
<code>// Custom event
public class PackApplicationEvent extends ApplicationEvent {
public PackApplicationEvent(Object source) {
super(source);
}
}
@Component
public class PackApplicationListener implements ApplicationListener<PackApplicationEvent> {
@Override
public void onApplicationEvent(PackApplicationEvent event) {
System.out.printf("Received event message: %s%n", event.getSource());
}
}
@Component
public class CommonService {
public CommonService(ApplicationEventPublisher eventPublisher) throws Exception {
// Start async thread to publish event
Thread t = new Thread(() -> {
eventPublisher.publishEvent(new PackApplicationEvent("Custom event"));
});
t.start();
// Main thread must wait for t to finish
t.join();
}
}
</code>In Spring 6.2 the problem is resolved through asynchronous bean initialization. For details see the linked article.
The main thread holds a lock on the singleton bean pool while waiting for t.join() to complete:
After the t thread starts, it publishes the event, which is handled by PackApplicationListener :
<code>protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
// ...
return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
private Collection<ApplicationListener<?>> retrieveApplicationListeners() {
for (String listenerBeanName : listenerBeans) {
// Retrieve bean instance from container
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
}
}
</code>The main and t threads are not deadlocked, but the main thread is blocked until the event processing finishes.
2. Bean Creation Callback Mechanism
Since Spring 6.2, SingletonBeanRegistry (the super‑interface of ConfigurableBeanFactory ) adds addSingletonCallback(String beanName, Consumer<Object> singletonConsumer) . This works like addBeanPostProcessor but is invoked after a bean is fully created, without modifying the bean instance itself.
<code>public class CommonService {}
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// Register callback for bean "cs" after it is fully created
beanFactory.addSingletonCallback("cs", obj -> {
System.err.println(obj);
});
try (GenericApplicationContext context = new GenericApplicationContext(beanFactory)) {
context.registerBean("cs", CommonService.class);
context.refresh();
}
</code>Implementation in DefaultSingletonBeanRegistry :
<code>public class DefaultSingletonBeanRegistry {
// Get singleton bean
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
// ...
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
protected void addSingleton(String beanName, Object singletonObject) {
// Retrieve registered callback
Consumer<Object> callback = this.singletonCallbacks.get(beanName);
if (callback != null) {
// Invoke callback
callback.accept(singletonObject);
}
}
}
</code>The call to singletonFactory.getObject() marks the completion of bean initialization.
3. Global Transaction Rollback Setting
By default Spring rolls back only RuntimeException . To roll back a checked exception, you must specify it explicitly:
<code>// Custom checked exception
public class BusinessException extends Exception {}
@Transactional
public void save() throws Exception {
this.jdbcTemplate.update("insert into t_person (age, name) values (?, ?)", 33, "China");
boolean flag = true;
if (flag) {
throw new BusinessException();
}
}
</code>Adding the exception to rollbackFor makes the transaction roll back:
<code>@Transactional(rollbackFor = {BusinessException.class})
</code>Spring 6.2 adds a new attribute to EnableTransactionManagement for global configuration:
<code>public @interface EnableTransactionManagement {
// Default: only roll back runtime exceptions
RollbackOn rollbackOn() default RollbackOn.RUNTIME_EXCEPTIONS;
}
</code>Usage example:
<code>@Configuration
@EnableTransactionManagement(rollbackOn = RollbackOn.ALL_EXCEPTIONS)
public class AppConfig {}
</code>With this setting, any exception triggers a rollback.
4. Performance Improvements
When an application contains thousands of @Component classes, startup can take minutes. Replacing @Autowired with @Resource reduces startup to under a minute. Five injection patterns were benchmarked:
Pattern1: @Inject
Pattern2: @Inject + @Named
Pattern3: @Autowired
Pattern4: @Autowired + @Qualifier
Pattern5: @Resource
Test results show @Inject and @Autowired variants exhibit O(N²) time, while @Resource runs in O(N) time, making it significantly faster.
Spring 6.2 also optimizes the algorithm for constructor‑based injection: when parameter names match bean names, the framework can resolve dependencies faster, further shortening startup time.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.