Статьи

Spring Async и Java 8 CompletableFuture

Известно, что я не самый большой поклонник Spring , но в настоящее время я работаю в организации, которая поддерживает слишком много проектов, использующих Spring (в разных формах и версиях). Я по-прежнему скептически отношусь к Spring, конечно, есть некоторые очень хорошие идеи, есть несколько хороших (слишком много) абстракций, есть несколько очень удобных «ярлыков» для запуска сложных проектов. Я не буду подробно останавливаться на том, что мне не нравится в этом посте.

Что мне нравится в документации Spring, так это их руководство по началу работы. Хорошо написано и конкретно. Я читал краткое руководство по выполнению метода Async через SpringBoot / RestApi [ ссылка ].

Так что это реализация примера метода «асинхронный» findUser (). Полный источник здесь .

1
2
3
4
5
6
7
8
@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);
}

Мне было интересно, почему в примере все еще есть «Будущее», в то время как мы представили Java8, CompletableFuture . Я предполагаю, что оригинальные авторы хотят сохранить обратную совместимость с предыдущими версиями Java (6/7) — там, где эта конструкция недоступна .

Кажется, у кого-то был такой же вопрос, и он написал очень хороший пример здесь . В одном из комментариев вы можете увидеть подсказку о том, что начиная с версии 4.2 и далее Spring API будет совместимо с использованием CompletableFuture поверх Future & AsyncResult, который уже предоставлен. Я подумал: « Ну, это позор, почему бы не попробовать или даже не задокументировать это, потому что если кто-то воспользуется этим примером, он / она может остаться в текущей реализации» — почему бы не использовать что-то стандартное ?.

Поэтому я решил внести небольшое изменение, удалить Future и заменить его на CompletableFuture, также закомментировать вызовы Future.isDone () и заменить его очень удобным методом CompletableFuture.allof () .

Поэтому я изменил тип возвращаемого значения в методе «service», обновив код вызывающего абонента — чтобы синхронизировать все 3 фьючерса, и после того, как allof () было выполнено, мы могли напечатать результаты.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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);
    }
 
}

Модифицированный пример можно найти здесь . Я нашел этот и этот пост в блоге от Томаша Ниркевича , очень приятного и прагматичного шага по CompletableFuture, богатому списку методов. Также есть довольно полная презентация моего любимого спикера Devoxx Жозе Паумарда, которую вы можете найти здесь .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@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());
    }

связи

Ссылка: Spring Async и Java CompletableFuture 8 от нашего партнера JCG Пэрис Апостолопулос в блоге журнала Papo .