spring boot: 비동기 처리하기

김아무개·2023년 6월 7일
0

Spring Boot 🍃

목록 보기
33/95

보고 배운 인강 링크

웹 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 가 붙은 스레드가 실행되어 동작하는 것까지 확인!

스레드 실행이 끝나면
반환 값이 request api에 출력되는것을 확인할 수 있다.

profile
Hello velog! 

0개의 댓글