Skip to content

Asynchronous initialization of beans during startup [SPR-14920] #19487

Closed
@spring-projects-issues

Description

@spring-projects-issues

Antonio Anzivino opened SPR-14920 and commented

Some projects take a few minutes to start up because of I/O operations required for their initialization. For example, one of my projects queries a European Central Bank web service as part of its init sequence, while other beans query the database to retrieve the initial data set.

In general, Spring initializes beans one by one on the same thread and it has been working safe so far.

It is quite a few years I was thinking to this: make bean initialization asynchronous.

I imagine the process like this: if a bean's initialization method (AsyncInitializingBean?) returns a Future<Void>, then Spring uses the default task executor to defer bean initialization and go to the next bean. Only when all the Futures return, the context is said to have initialized.

If a bean has a dependency on an asynchronous bean, then obviously its initialization cannot start before the dependent asynchronous bean has initialized.

I am opening this ticket to get feedback from the community.

And now let's talk about the workaround, because there is one. A developer can speed up the context init process by manually deferring I/O operations after init, but then the developer has to make sure that beans calling it in an uninitialized state (before the deferred initialization completes) get a consistent result, e.g. implementing locks on all methods. This works but requires a lot more code.

Example:

public class AsyncWorkaround1Bean {

    private boolean inited = false;

    @PostConstruct
    public void init() {
        this.taskExecutor.submit(() -> doAsyncInit());
    }


    private void doAsyncInit() {
        ........
        inited = true;
    }


    public List getData() {
         if (!inited) throw new NotReadyYetException();
    }
}

public class AsyncWorkaround2Bean {

    private boolean inited = false;
    private final Object lock = new Object();

    @PostConstruct
    public void init() {
        this.taskExecutor.submit(() -> doAsyncInit());
    }


    private void doAsyncInit() {
        ........
        inited = true;
        synchronized(lock) {
            lock.notifyAll();
        }
    }


    public List getData() {
        while (!inited)
            synchronized(lock) {
                lock.wait;
            }
    }
}

Thanks for your feedback


Issue Links:

2 votes, 4 watchers

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions