Dmitry
Dmitry

Reputation: 35

Reactive calls in @PostConstruct function

Could somebody help me to do the following:

@PostContruct public void func() {
   webclient.get()...subscribe();
}

webclient call will terminate after func() returns. Most likely it will happen before the first request comes in, but no guarantees. The other option is to block(), which defeats the purpose of being reactive.

What would be the right way to make reactive calls in @PostConstruct methods?

Thank you.

Upvotes: 1

Views: 1770

Answers (2)

rcomblen
rcomblen

Reputation: 4649

You can use toFuture to use the standard Java async mechanisms:

@PostConstruct
public void postConstruct() throws ExecutionException, InterruptedException {
    log.info("Start postConstruct");
    WebClient webClient = WebClient.create();
    webClient.get().uri(...).retrieve()
        .toEntity(String.class)
        .flatMap((responseEntity) -> {
            log.info("Data retrieved.");
            return Mono.just(true);
         })
         .toFuture()
         .get();
    log.info("Setup complete");
}

And you'll get in the logs:

Start postConstruct
Data retrieved
Setup complete

In that order ...

Upvotes: 0

vins
vins

Reputation: 15400

I created a simple bean.

Synchronous update:

@Component
public class BeanTest {

    private String postConstructValue;

    @PostConstruct
    public void init(){
        try {
            Thread.sleep(5000);
            this.postConstructValue = "Construction done";
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Scheduled(fixedRate = 500)
    public void print(){
        System.out.println(
                this.postConstructValue
        );
    }

}
  • It took some time for app to start (more than 5 seconds) because we simulated some time consuming process in the post construct. Scheduled print method started printing only after the app started. It started printing "Construction done" message.

Asynchronous update:

@Component
public class BeanTest {

    private String postConstructValue;

    @PostConstruct
    public void init(){
        Flux.just("Construction done")
                .delayElements(Duration.ofSeconds(5))
                .subscribe(s -> this.postConstructValue = s);
    }

    @Scheduled(fixedRate = 500)
    public void print(){
        System.out.println(
                this.postConstructValue
        );
    }

}
  • Now in this approach, the app started within 2 seconds. Print method starting printing null for few seconds. Then it started printing "Construction done". It does not terminate the Flux postConstruct value update. It happened asynchronously.

Reactive approach is good when you want a non-blocking behavior and getting something done asynchronously. If you think that your component creation should wait for proper construction, you have to block! Otherwise, you can go with second approach.

Upvotes: 1

Related Questions