Backend Development 9 min read

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.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
How Spring 6.2 Eliminates Bean Initialization Blocking and Boosts Startup Speed

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&lt;Object&gt; 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.

Javaperformance optimizationSpringmultithreadingTransaction ManagementBean Initialization
Spring Full-Stack Practical Cases
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.