Статьи

Вызов асинхронного вызова метода с использованием объекта Future в Spring

Следующий пример продемонстрирует вызов асинхронного метода внутри контейнера Spring. Зачем нам нужны асинхронные вызовы методов? В некоторых случаях мы действительно не знаем, ожидается ли повтор или когда результат должен быть возвращен. Традиционный способ В мире Java EE для обработки асинхронных вызовов используется очередь / тема. Мы могли бы сделать то же самое в Spring, но если понадобится простой асинхронный вызов, вы можете легко сделать это, выполнив следующие шаги:

1. Объявите асинхронный шлюз:

1
2
3
4
<bean id="executionLogicImpl"
 class="com.test.components.execution_gateway.ExecutionLogicImpl"
 abstract="false" lazy-init="default" autowire="default">
 </bean>

2. объявить метод интерфейса с типом возврата — Future (Java 5+):

Дополнительная информация об объекте Future: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Future.html.

1
2
3
4
5
6
public interface ExecutionLogic
{
 
 public Future<String> doSomeExecutionLogic(String message);
 
}

* Как только GatewayProxyFactoryBean заметит тип возвращаемого значения Future, он переключит метод в асинхронный режим, имея AsyncTaskExecutor

3. Мы создадим канал задания, который будет собирать все запросы и асинхронно отправлять их другому классу (ExecutionLogicImpl) для их обработки (некоторая случайная бизнес-логика):

1
2
3
<int:channel id="job1Channel" />
 
<int:service-activator input-channel="job1Channel" ref="executionLogicImpl" method="doSomeExecutionLogic" />

Класс ExecutionLogicImpl:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
public class ExecutionLogicImpl
{
 public String doSomeExecutionLogic(String msg)
 {
 try
 {
 System.out.println("doing long work on message="+msg);
 Thread.sleep(8000);
 
}
 catch (InterruptedException e)
 {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }
 return msg + "_completed";
 
}
 
}

Тестовый класс:

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
30
31
32
33
34
import com.test.components.execution_gateway.ExecutionLogic;
 
public class testExeceution
 
{
 
...
ExecutionLogic executionLogic;
public String sendMsgToExecutionQueue(String msg)
 {
 Future<String> processedMessage = executionLogic.doSomeExecutionLogic(msg);
 
String finalResult = "";
 try
 {
 finalResult = " " + processedMessage.get(TIMEOUT, TimeUnit.SECONDS);
 return "1 final result: " + finalResult; // + " " + response;
 }
 catch (ExecutionException e)
 {
 return "1 final result: " + e + finalResult;// + " " + response;
 }
 catch (TimeoutException tex)
 {
 return "1 final result: " + tex + finalResult; // + " " + response;
 }
 catch (Exception ex)
 {
 return "1 final result: " + ex + finalResult;// + " " + response;
 }
 
}
...
}

* Вы можете включить тайм-аут, используя объект Future для случаев, когда ответ никогда не будет возвращен.

Так что здесь происходит? Мы отправляем ввод для выполнения асинхронно. Отправитель ожидает ответа (асинхронно), как только запрос завершит свою обработку, результат будет отправлен обратно отправителю.