Enterprise Java

Spring Async and Java’s 8 CompletableFuture

It is known that I am not the biggest fan of Spring, but at the time being I work for an organization that maintains too many projects utilizing Spring (in different forms and versions). I still remain skeptic towards Spring, of course there are some very nice ideas, there are some nice (too many) abstractions, there are some very handy ‘shortcuts’ to bootstrap complex projects. I am not going to elaborate on the things I don’t like in this post.

One thing I like on Spring’s documentation, is their getting started guides. Well written and concrete. I was reading through, a short guide, for ‘ Async‘ method execution, through SpringBoot /RestApi [ link] .

So this is this the implementation of the example ‘asynchronous’ findUser() method. Full source here.

@Async
public Future<User> findUser(String user) throws InterruptedException {
  System.out.println("Looking up " + user);
  User results = restTemplate.getForObject("https://api.github.com/users/" + user, User.class);
  // Artificial delay of 1s for demonstration purposes
  Thread.sleep(1000L);
  return new AsyncResult<User>(results);
}

I was wondering why there is still a ‘ Future’ in the example, while we have been introduced Java8, CompletableFutureI guess the original authors want to preserve backwards compatibility with previous versions of Java (6 / 7 ) – where this construct is not available.

It seems that someone else had the same question, and wrote a very nice example here. In one of the comments, you can see a hint that from version 4.2 and onward the Spring API, would be compatible with the use of CompletableFuture, on top of Future & AsyncResult which are already provided. I thought, ` well it’s a shame, why not try it or even document it, because if someone lands on this example, he/she might stay with the current implementation` – why not use something standard?.

So I decided to make a tiny change, remove Future and replace it with CompletableFuture, also comment out the calls to Future.isDone() and replace it with the very handy CompletableFuture.allof() method.

So I changed the return type on the ‘service’ method while, updating the, caller code – to sync on all 3 futures and once allof() them were done, we could print the results.

package hello;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class GitHubLookupService {

    RestTemplate restTemplate = new RestTemplate();

    @Async
    public CompletableFuture findUser(String user) throws InterruptedException {
        System.out.println("Looking up " + user);
        User results = restTemplate.getForObject("https://api.github.com/users/" + user, User.class);
        // Artificial delay of 1s for demonstration purposes
        Thread.sleep(1000L);
        return CompletableFuture.completedFuture(results);
    }

}

The modified, example can be found here. I found this and this blog posts from Tomasz Nirkewicz, a very nice and pragmatic walk through of CompletableFuture, rich method list. There is also a quite complete presentation by my favorite Devoxx Speaker , Jose Paumard you can find it here.

@Override
    public void run(String... args) throws Exception {
        // Start the clock
        long start = System.currentTimeMillis();

        // Kick of multiple, asynchronous lookups
        CompletableFuture page1 = gitHubLookupService.findUser("PivotalSoftware");
        CompletableFuture page2 = gitHubLookupService.findUser("CloudFoundry");
        CompletableFuture page3 = gitHubLookupService.findUser("Spring-Projects");

        // Wait until they are all done
        //while (!(page1.isDone() && page2.isDone() && page3.isDone())) {
          //  Thread.sleep(10); //10-millisecond pause between each check
        //}

        //wait until all they are completed.
        CompletableFuture.allOf(page1,page2,page3).join();
        //I could join as well if interested.

        // Print results, including elapsed time
        System.out.println("Elapsed time: " + (System.currentTimeMillis() - start) +" ms");
        System.out.println(page1.get());
        System.out.println(page2.get());
        System.out.println(page3.get());
    }

Links

Reference: Spring Async and Java’s 8 CompletableFuture from our JCG partner Paris Apostolopoulos at the Papo’s log blog.

Paris Apostolopoulos

Paris is a senior software engineer focusing on J2EE development, loves Business process modelling and is keen on software quality challenges. He is passionate about Java and Java communities. He is a co-founder and administrator of the first Java User Group in greece(JHUG.gr) and occasional speaker on meet-ups and seminars and regular blogger. For his contributions and involvement on the Java community he has been awarded the title of Java Champion in 2007 by Sun Microsystems.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button