Spring - Asynchronous request processing (비동기 요청 처리)
Spring - Asynchronous request processing (비동기 요청 처리)
1. pom.xml
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
2. web.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
...
</web-app>
3. web.xml 내의 servlet설정에 async-supported 태그 값을 true로 설정한다.
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
종류
1.Callable
요청을 처리하는 Servlet쓰레드가 반환되면 Spring MVC에서 제어하는 쓰레드에 의해 비동기처리된다.
Callable의 처리과정은 다음과 같다.
-
Controller의 RequestMapping method에서 일반적인 뷰 객체나 String값을 리턴하는 것이 아니라 Callable객체를 리턴한다.
-
Callable이 리턴될 때 Servlet쓰레드가 반환되며 비동기처리를 Callable에게 위임한다.
-
Spring MVC내의 TaskExcutor에서 관리되는 쓰레드에서 Async처리가된다.
-
Callable내부의 call()함수에서 리턴되는 값이 다시 Servlet쓰레드로 전달된다.
Callable은 주로 요청처리가 오래걸리는 DB작업, REST API요청처리를 하는 데 적합하다.
@RequestMapping(“/view”)
public Callable<String> callableWithView(final Model model) {
return new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(2000);
model.addAttribute(“foo”, “bar”);
model.addAttribute(“fruit”, “apple”);
return “view”;
}
}
2. DefferedResult
Servlet 스레드는 반환하고 Spring MVC가 제어하지 않는 쓰레드를 통해 비동기를 처리한다. DefferedResult는 JMS, AMQP, 스케쥴러, Redis, 다른 HTTP요청에서 사용된다.
DefferedResult의 처리과정은 다음과 같다.
-
Controller에서 DefferedResult를 반환하고 In-Memory Queue또는 List에 DefferedResult를 저장한다.
-
Servlet쓰레드는 반환되고 이벤트 발생 시 Queue에서 DefferedResult객체를 꺼내 사용한다.
@RequestMapping("/quotes")
@ResponseBody
public DeferredResult<String> quotes() {
DeferredResult<String> deferredResult = new DeferredResult<String>();
// Save the deferredResult in in-memory queue ...
queue.add(defferedResult);
return deferredResult;
}
// In some other thread...
@RequestMapping("/someEvent")
@ResponseBody
public String someEvent(String data) {
for(DefferedResult<String> result : queue) {
result.setResult(data);
}
return "view";
}
3. AsyncTask
Callable과 동일한 방식으로 사용하며 Controller에서 Callable을 담아서 반환한다.
Timeout을 추가할 수 있으며 AsyncTaskExecutor를 지정하거나 작업의 종류에 따라 쓰레드 풀을 분리하여 사용할 수 있다.
@RequestMapping("/facebooklink")
public WebAsyncTask<String> facebooklink() {
return new WebAsyncTask<String>(
30000L, // Timeout
"facebookTaskExecutor", // TaskExecutor
new Callable<String>() {
@Override
public String call() throws Exception {
// 작업
return result;
}
}
);
}