Spring @Async vs Spring WebFlux
글을 작성하게된 계기
실무에서 서버간 통신을 할때 비동기로 호출해야하는 경우가 있었다. 처음에는 @Async를 사용하였는데 좀 더 깊게 파보니 Spring WebFlux도 많이 사용하는 것을 확인하고 WebFlux도 동시에 써보았는데 WebFlux가 더 빠른 것을 보았다.
Spring @Async
설명
@Async
어노테이션은 Spring에서 제공하는 비동기 실행 방법으로 메서드를 별도의 스레드에서 비동기적으로 실행한다.
@Async
는 Spring의 AOP 기능을 활용하여 메서드 호출을 비동기적으로 처리한다. 이는 스레드 풀을 사용하여 별도의 스레드에서 실행되며, 비동기 작업의 결과 또는 상태는 Future
객체를 통해 관리할 수 있다. @Async
는 간단하고 효율적인 비동기 처리 방법을 제공하여, 리소스를 효율적으로 사용하면서 애플리케이션의 성능을 향상시킬 수 있다.
적용 사례
@Async
는 주로 단일 작업에 대한 비동기 처리가 필요할 때 사용됩니다. 예를 들어, 이메일 보내기, 파일 업로드, 복잡한 계산 수행 등의 작업에 적합합니다.
장점
구현이 간단하고, 기존 코드에 쉽게 통합할 수 있다.
단점
복잡한 비동기 작업 흐름이나 백프레셔(backpressure) 관리 등에는 적합하지 않다.
예시 코드
@Configuration
@EnableAsync
public class AsyncConfig {
// 필요한 경우 여기에 사용자 정의 스레드 풀 설정을 추가할 수 있습니다.
}
public class AsyncService {
@Async(name = 'test')
public void asyncTest() {
try {
Thread.sleep(1000);
log.info("Async Test");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Spring Webflux
설명
Spring WebFlux
는 Spring 5에서 도입된 반응형 프로그래밍을 위한 웹 프레임워크이다. 이는 논블로킹(non-blocking) I/O와 비동기적 실행을 지원하며, 더 효율적인 리소스 사용과 높은 처리량을 제공한다. Mono
와 Flux
와 같은 리액티브 타입을 사용하여 데이터 스트림을 처리한다.
적용사례
WebFlux는 동시에 많은 요청을 처리해야 하거나, 데이터 스트림을 연속적으로 처리해야 할 때 유용하다. 예를 들어, 실시간 데이터 처리, 대규모 파일 처리, 웹 소켓 통신 등에 적합하다.
장점
높은 동시성 처리 능력, 리소스 효율성, 백프레셔 관리 기능을 제공한다.
단점
비동기와 반응형 프로그래밍 모델은 학습 곡선이 높으며, 복잡할 수 있다.
예시 코드
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient() {
return WebClient.create("http://example.com/api"); // 여기에 외부 API의 기본 URL을 설정합니다.
}
}
@Configuration
public class RouterConfig {
@Bean
public RouterFunction<ServerResponse> personRouter(PersonHandler handler) {
return route(GET("/person/{id}"), request -> handler.getPerson(request.pathVariable("id")))
.andRoute(GET("/persons"), request -> handler.getAllPersons());
}
}
@Component
public class ApiService {
public Mono<String> getExternalData() {
return webClient.get()
.uri("/data") // 외부 API의 특정 경로
.retrieve()
.bodyToMono(String.class); // 응답을 String으로 변환
}
}
@RestController
public class ApiController {
private final ApiService apiService;
@Autowired
public ApiController(ApiService apiService) {
this.apiService = apiService;
}
@GetMapping("/external-data")
public Mono<String> fetchExternalData() {
return apiService.getExternalData(); // 서비스에서 외부 API 호출
}
}