[Spring] @Async를 이용한 비동기 처리
Updated:
1. 개요
게시판에서 내가 쓴 글에 댓글이 달린 경우 나에게 알림이 오도록 구현한다고 가정해보자. 1) 댓글 작성 2) 알림
두 가지 기능으로 나눠서 생각해 볼 수 있는데, 알림 기능은 부가적인 기능이므로 댓글 작성 기능에 영향을 주면 안 된다. 예를 들어 댓글 작성 후 알림 처리가 지연되는 경우 댓글작성 자체를 지연하는 것이 아니라, 댓글 작성은 완료시키고 다른 Thread에서 알림을 처리할 수 있을 것이다. 이럴 때 활용 가능한 것이 비동기인데, 스프링에서는 @Async Annotation을 이용하여 간단하게 비동기 처리를 할 수 있다.
2. 개발 환경
-
Java 11
-
Spring Boot 2.5.3
3. AsyncConfigurer 구현
@EnableAsync Annotation을 추가하기만 해도 비동기 처리가 가능하지만, 이 경우 요청마다 매번 새로운 Thread를 생성하는 Default 설정이 적용된다. 따라서 Pool에 정해진 개수만큼 Thread를 미리 생성해놓고, 필요할 때마다 가져가서 사용할 수 있도록 AsyncConfigurer 인터페이스의 구현이 필요하다.
[AsyncConfig.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
int processors = Runtime.getRuntime().availableProcessors();
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(processors);
executor.setMaxPoolSize(processors * 2);
executor.setQueueCapacity(50);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("AsyncExecutor-");
executor.initialize();
return executor;
}
}
Line 2 : 스프링의 비동기 기능을 활성화 하여 Async Annotation 감지
Line 7 : 본인 PC의 Processor 개수를 얻어옴
Line 8 : Thread Pool을 편리하게 관리해주는 클래스
Line 9 : 기본 Thread 개수
Line 10 : 최대 Thread 개수 (Queue가 가득 찬 이후 MaxPoolSize만큼 생성)
Line 11 : 대기를 위한 Queue의 크기
Line 12 : Thread 재사용 시간
Line 13 : Thread 이름의 Prefix
Line 14 : ThreadPoolExecutor 생성
4. Async Method 구현
[TestService.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Slf4j
@Service
public class TestService {
@Async
public void asyncMethod() {
log.info("----- Async Start -----");
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("----- Async End -----");
}
}
Line 5 : 해당 메서드를 비동기로 사용하기 위한 @Async Annotation 추가
5. 테스트
[TestController.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Slf4j
@RestController
@RequiredArgsConstructor
public class TestController {
private final TestService testService;
private final ApplicationEventPublisher eventPublisher;
@GetMapping("/asyncTest")
public void asyncTest() {
log.info("----- Test Start -----");
testService.asyncMethod();
log.info("----- Test End -----");
}
}
[테스트 결과]
의도했던 것처럼 다른 Thread에서 비동기로 처리되는 것을 확인할 수 있다.
Leave a comment