Статьи

Spring and Threads: Async

Ранее мы начали работать с Spring и TaskExecutor , таким образом, мы стали более знакомыми с тем, как использовать потоки в приложении Spring .

Однако использование исполнителя задач может быть обременительным, особенно когда нам нужно выполнить простое действие.

Асинхронные методы Spring приходят на помощь.

Вместо того, чтобы связываться с runnables и TaskExecutor, вы торгуете управлением исполнителя для простоты асинхронных функций.
Чтобы выполнить вашу функцию в другом потоке, все, что вам нужно сделать, это аннотировать ваши функции аннотацией @Async.

Асинхронные методы имеют два режима.

Режим огня и забывания: метод, который возвращает тип void.

1
2
3
4
5
6
7
@Async
    @Transactional
    public void printEmployees() {
 
        List<Employee> employees = entityManager.createQuery("SELECT e FROM Employee e").getResultList();
        employees.stream().forEach(e->System.out.println(e.getEmail()));
    }

Режим поиска результатов: метод, который возвращает тип будущего.

1
2
3
4
5
6
@Async
    @Transactional
    public CompletableFuture<List<Employee>> fetchEmployess() {
        List<Employee> employees = entityManager.createQuery("SELECT e FROM Employee e").getResultList();
        return CompletableFuture.completedFuture(employees);
    }

Обратите особое внимание на то, что аннотации @Async не работают, если они вызываются «this». @Async ведет себя так же, как аннотация @Transactional. Поэтому вам нужно, чтобы ваши асинхронные функции были общедоступными. Вы можете найти больше информации в документации по aop прокси .

Однако использование только аннотации @Async недостаточно. Нам нужно включить возможность выполнения асинхронного метода Spring с помощью аннотации @EnableAsync в одном из наших классов конфигурации.

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
26
27
28
29
package com.gkatzioura.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 
import java.util.concurrent.Executor;
 
/**
 * Created by gkatzioura on 4/26/17.
 */
@Configuration
@EnableAsync
public class ThreadConfig {
 
    @Bean
    public TaskExecutor threadPoolTaskExecutor() {
 
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(4);
        executor.setThreadNamePrefix("sgfgd");
        executor.initialize();
 
        return executor;
    }
 
}

Следующий вопрос — как мы объявляем ресурсы и пулы потоков, которые будут использовать асинхронные функции. Мы можем получить ответ из документации .

По умолчанию Spring будет искать определение связанного пула потоков: либо уникальный компонент TaskExecutor в контексте, либо компонент Executor с именем «taskExecutor» в противном случае. Если ни один из них не является разрешимым, SimpleAsyncTaskExecutor будет использоваться для обработки вызовов асинхронных методов.

Однако в некоторых случаях мы не хотим, чтобы один и тот же пул потоков выполнял все задачи приложения. Мы могли бы хотеть отдельные пулы потоков с различными конфигурациями, поддерживающими наши функции.

Для этого мы передаем аннотации @Async имя исполнителя, который мы можем использовать для каждой функции.

Например, настроен исполнитель с именем «specificTaskExecutor».

01
02
03
04
05
06
07
08
09
10
11
12
13
@Configuration
@EnableAsync
public class ThreadConfig {
 
    @Bean(name = "specificTaskExecutor")
    public TaskExecutor specificTaskExecutor() {
 
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.initialize();
        return executor;
    }
 
}

Затем наша функция должна установить значение квалификатора, чтобы определить целевого исполнителя конкретного исполнителя или TaskExecutor.

1
2
3
4
@Async("specificTaskExecutor")
public void runFromAnotherThreadPool() {
    System.out.println("You function code here");
}

В следующей статье мы поговорим о транзакциях по потокам.

Вы можете найти исходный код на github .

Опубликовано на Java Code Geeks с разрешения Эммануила Гкациоураса, партнера нашей программы JCG. Смотрите оригинальную статью здесь: Spring и Threads: Async

Мнения, высказанные участниками Java Code Geeks, являются их собственными.