-
비동기 프로그래밍 구현[공부] 프로그래밍/Spring・Spring Boot (JAVA) 2024. 5. 20. 12:42
♧ 전체 코드 : https://github.com/woodisco/AsyncGitHub - woodisco/Async: async 공부
async 공부. Contribute to woodisco/Async development by creating an account on GitHub.
github.com
Spring에서 비동기 프로그래밍을 하기 위해서는 ThreadPool을 정의할 필요가 있다.
▷ ThreadPool을 생성해야 하는 이유?
=> 비동기는 Main Thread가 아닌 Sub Thread에서 작업을 진행하며 Java에서는 ThreadPool을 생성하여 Async 작업을 처리한다.
▷ ThreadPool 생성 옵션- CorePoolSize : 최소한의 Thread를 몇개를 가기고 있을 것이냐를 지정하는 옵션
- MaxPoolSize : 최대 몇 개까지 Thread를 할당할 것인가를 지정하는 옵션
- KeepAliveTime : 지정한 시간만큼 Thread들이 작동하지 않으면 반환하는 옵션
- WorkQueue : 자료구조인 큐를 사용하여 WorkQueue라는 곳에 많은 요청을 보관하는 옵션
▷ ThreadPool 생성시 주의사항
- CorePoolSize 값을 너무 크게 설정할 경우 side effect 고려하기
- IllegalArgumentException 주의 :
CorePoolSize < 0
KeepAliveTime < 0
MaximumPoolSize <= 0
MaximumPoolSize < CorePoolSize- NullPointerException : WorkQueue is Null
▷ ThreadPool 정리
if (Thread 수 < CorePoolSize) new Thread 생성 if (Thread 수 > CorePoolSize) Queue에 요청 추가 if (Queue Full && Thread 수 > MaxPoolSize) 요청 거절 if (Queue Full && Thread 수 < MaxPoolSize) new Thread 생성
비동기 프로그래밍 구현
① AppConfig 작성
@Configuration public class AppConfig { @Bean(name = "defaultTaskExecutor", destroyMethod = "shutdown") public ThreadPoolTaskExecutor defaultTaskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(200); executor.setMaxPoolSize(200); return executor; } @Bean(name = "messagingTaskExecutor", destroyMethod = "shutdown") public ThreadPoolTaskExecutor messagingTaskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(200); executor.setMaxPoolSize(200); return executor; } }
▷ destroyMethod = "shutdown"
Bean이 소멸될 때 shutdown 메서드를 호출하여 스레드 풀을 안전하게 종료한다. 이는 스레드 풀이 더 이상 새로운 작업을 받지 않게 하고, 현재 진행 중인 작업이 완료될 때까지 기다렸다가 스레드를 종료한다.② AsyncConfig 작성
@Configuration @EnableAsync public class AsyncConfig { }
Spring의 비동기 처리 기능을 활성화하는 애노테이션이다. 이를 통해 Spring은 @Async 애노테이션이 붙은 메서드들을 백그라운드 스레드에서 비동기적으로 실행할 수 있다.
③ AsyncController 작성
④ EmailService 작성@Service @RequiredArgsConstructor public class EmailService { @Async("defaultTaskExecutor") public void sendMail() { System.out.println("[sendMail] :: " + Thread.currentThread().getName()); } @Async("messagingTaskExecutor") public void sendMailWithCustomThreadPool() { System.out.println("[sendMailWithCustomThreadPool] :: " + Thread.currentThread().getName()); } }
@Async 을 사용할때에는 무조건 public을 사용해야 한다. private 을 사용시 에러 발생.
⑤ AsyncService 작성
@Service @RequiredArgsConstructor public class AsyncService { private final EmailService emailService; // ① Bean을 주입받은 경우 : 비동기 프로그래밍 가능 public void asyncCall_1() { System.out.println("[asyncCall_1] :: " + Thread.currentThread().getName()); emailService.sendMail(); emailService.sendMailWithCustomThreadPool(); } // ② 인스턴스를 이용한 경우 : 비동기 프로그래밍 불가능 public void asyncCall_2() { System.out.println("[asyncCall_2] :: " + Thread.currentThread().getName()); EmailService emailService = new EmailService(); emailService.sendMail(); emailService.sendMailWithCustomThreadPool(); } // ③ 내부의 @Async를 이용한 경우 : 비동기 프로그래밍 불가능 public void asyncCall_3() { System.out.println("[asyncCall_3] :: " + Thread.currentThread().getName()); sendMail(); } @Async public void sendMail() { System.out.println("[sendMail] :: " + Thread.currentThread().getName()); } }
curl localhost:8080/1 을 실행하면 아래와 같이 로그가 출력되며, 비동기를 구현할 수 있다.
하지만 curl localhost:8080/2 혹은 curl localhost:8080/3 의 경우에는 아래와 같이 로그가 출력되며, 비동기를 구현 할 수 없게 된다.
비동기를 구현할 때에는 무조건 Bean을 주입받은 형태로 구현을 해야 한다.
그 이유는 Spring Framework가 비동기로 처리하고자 하는 메서드를 즉 EmailService를 Bean을 등록해서 순수한 Bean을 AsyncService에 반환을 해주는 것이 아니라 Async 하게 동작을 해야 하기 때문에 한번 더 wrapping을 해서 반환을 하게 된다.
즉 프록시 객체로 wrapping을 한 후 프록시 객체를 반환하게 된다. 그럼 AsyncService에서는 비동기로 처리할 수 있게 emailService.sendMail() 처리를 Sub Thread에게 위임을 하게 된다.
※ 프록시 객체 :
프록시 객체는 원래 객체와 동일한 인터페이스를 구현하거나 상속받아, 원래 객체의 메서드 호출을 가로채서 처리할 수 있는 객체이다. 프록시를 사용하면 메서드 호출 전후에 추가 로직을 삽입할 수 있다.출처 : 패스트캠퍼스 10개 프로젝트로 완성하는 백엔드 웹개발(Java/Spring) 초격차 패키지 Online
'[공부] 프로그래밍 > Spring・Spring Boot (JAVA)' 카테고리의 다른 글
Feign Client 구현 - 2 (0) 2024.05.21 Feign Client 구현 - 1 (0) 2024.05.21 Spring Multi Module 구현 (0) 2024.05.16 Spring Batch 구현 - 7 (0) 2024.05.14 Spring Batch 구현 - 6 (0) 2024.05.09