-
spring boot: 비동기 처리하기Spring Boot 🍃 2023. 12. 5. 00:01
웹 MVC에서는 많이 사용할 일이 없다고 하지만,
비동기에 대한 호기심을 풀어내기 위해 간단히 학습!
만약 DB를 사용할 때 비동기를 사용해야 한다면
NoSQL
을 사용할 때는Spring WebFlux
를 사용하는 것을 추천RDB를 사용하게 된다면 여기서 사용하는 @Async 가 소용이 없다. 왜냐하면 트랜잭션 때문에 동기 방식으로 통신을 해야하기 때문에 전체적인 flow 자체가 비동기가 될 수 없다고 한다.
이러한 부분들은 spring 보다는 웹의 난이도, 아키텍처의 난이도가 올라갔을 때 경험해보게 될 수도 있는 부분이라고 강사님이 설명해주셨다.
이번 강의는 Spring WebFlux가 아닌, WebMvc에서도 이런식으로 코딩이 가능하다는 것을 체험해보기 위한 강의!
간단 실습
1. Application 파일에 어노테이션 추가
@EnableAsync
어노테이션을 추가해주어야 한다.@SpringBootApplication @EnableAsync public class AsyncApplication { public static void main(String[] args) { SpringApplication.run(AsyncApplication.class, args); } }
2. Service 파일 작성
간단한 테스트를 위해 service 파일에서
비동기 동작을 하는 api 격으로 hello() 메서드를 작성해주고,
hello() 메서드를 실행해서 controller로 결과값을 보낼 run() 메서드를 작성해준다.
run() 메서드에는
@Async
어노테이션을 붙여준다.이 때, @Async 어노테이션은 Proxy 패턴을 타기 때문에 public 메서드에만 사용할 수 있다.
@Async 어노테이션의 옵션으로, 등록된 bean의 이름을 입력해 줄 수 있음.
이 때 bean은 thread pool 설정 bean임!
그리고 지금은 간단한 사용 경험을 위해서 간단하게 작성했지만,
CompletableFuture를 사용할 경우
여러개 . 3~4개의 api를 CompletableFuture로 받은 다음 , 결과 값을 합쳐서 사용하는 형태를 권장한다.
@Slf4j @Service public class AsyncService { @Async("async-thread") public CompletableFuture<String> run() { return CompletableFuture.completedFuture(hello()); } public String hello() { for (int i = 0; i < 10; i++) { try { Thread.sleep(2000); log.info("thread sleep ... {}", i); } catch (InterruptedException e) { e.printStackTrace(); } } return "async hello"; } }
3. Controller 파일 작성
@Slf4j @RestController @RequestMapping("/api") @RequiredArgsConstructor public class ApiController { private final AsyncService asyncService; @GetMapping("/hello") public CompletableFuture<String> hello() { log.info("completable future init"); return asyncService.run(); } }
(안해도 됨) 4. Spring Thread Pool 설정
이 부분은
Spring의 Thread Pool 관리
에 대해 잘 알고 나서 건드려야 좋다. (일단 궁금해서 한 번만 찾아본 정리 잘 된 것 같은 링크 : jaehoney.tistory)Thread Pool 관련 내용이 무척 방대하고,
거대한 프로젝트가 아니라면 사용할 일이 거의 없기 때문에
지금은 이렇게 사용하는구나~ 정도로만 알아두고
추후에 공부할 게 없을 때나, 실무에서 스레드를 구현하게 되었을 때 공부해도 늦지 않다고 한다!
Spring의 Thread Pool에 대해 알고난 후 ThreadPoolTaskExecutor 학습 추천
@Configuration public class AppConfig { @Bean("async-thread") public Executor asyncThread() { ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); threadPoolTaskExecutor.setMaxPoolSize(100); threadPoolTaskExecutor.setCorePoolSize(10); // core 10개를 다 사용하면 queue에 내용이 들어감 threadPoolTaskExecutor.setQueueCapacity(10); // queue까지 10개가 다 차면 core 크기만큼 한번 더 늘어남 threadPoolTaskExecutor.setThreadNamePrefix("Async-"); // 스레드에 시작 이름 붙임 return threadPoolTaskExecutor; } }
5. 실행 !
Request API를 이용해 controller의 주소로 요청을 보내면 응답을 기다리는 (코딩을 그렇게 함) 상태가 된다.
스레드 동작 확인 메인 스레드에서 동작하지 않고, 새로운 스레드에서 동작하는 것을 확인할 수 있다. 그리고 AppConfig 파일에서 설정해준 name prefix 가 붙은 스레드가 실행되어 동작하는 것까지 확인!
'Spring Boot 🍃' 카테고리의 다른 글
Spring boot: RestTemplate - Naver 지역 검색 api 연동해보기 (0) 2023.12.05 spring boot : RestTemplate (0) 2023.12.05 Spring Boot: Interceptor 인터셉터 (0) 2023.12.05 spring boot: Slf4j (0) 2023.12.05 Spring Boot: Filter (0) 2023.12.04