개요
Spring Cloud Gateway 애플리케이션을 구동하게 되면 기존의 임베디드 톰켓 기반의 Spring Boot Web 애플리케이션과는 다르게 Netty 기반의 비동기 통신을 지원하는 형태의 웹 애플리케이션으로 실행됩니다.
이 문서에서는 왜 이러한 현상이 발생하는지 알아봅니다.
WebApplicationType
먼저 SpringBoot에서는 웹 애플리케이션 구동시 org.springframework.boot.WebApplicationType을 정하게 됩니다.
WebApplicationType
에는 세가지 타입이 존재합니다.
- WebApplicationType.SERVLET
→ 애플리케이션을 서블릿 기반의 웹 애플리케이션으로 실행하며 임베디드 서블릿 웹서버(기본적으로 tomcat 기반)로 실행한다. - WebApplicationType.REACTIVE
→ 애플리케이션을 리엑티브 웹 애플리케이션으로 실행하며 임베디드 리엑티브 웹 서버(기본적으로 netty 기반)로 실행한다 - WebApplicationType.NONE
→ 애플리케이션을 웹 애플리케이션, 임베디드 웹 서버로써 실행하지 않는다.
이제 어떠한 기준으로 WebApplicationType
을 가져가는지가 중요한데요. 간단하게 말하면 아래와 같은 기준을 가집니다.
- WebApplicationType.SERVLET →
spring-boot-starter-web
의존성을 가지면 해당 타입 - WebApplicationType.REACTIVE →
spring-boot-starter-webflux
의존성을 가지면 해당 타입 - WebApplicationType.NONE → 둘 다 의존성이 존재하지 않는다면 NONE 타입
둘 다 의존성이 존재한다면 SERVLET 타입으로 동작합니다. 이유는 아래 코드를 보면 알 수 있는데요.
...
package org.springframework.boot;
...
public enum WebApplicationType {
...
private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";
private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";
...
static WebApplicationType deduceFromApplicationContext(Class<?> applicationContextClass) {
if (isAssignable(SERVLET_APPLICATION_CONTEXT_CLASS, applicationContextClass)) {
return WebApplicationType.SERVLET;
}
if (isAssignable(REACTIVE_APPLICATION_CONTEXT_CLASS, applicationContextClass)) {
return WebApplicationType.REACTIVE;
}
return WebApplicationType.NONE;
}
...
}
WebApplicationType
을 결정할 때 spring-boot-starter-web
의존성 내에 존재하는 애플리케이션 컨텍스트 클래스를 먼저 스캔하기 때문입니다.
둘 다 존재하더라도 임의로 WebApplicationType을 REACTIVE로 명시한다면 REACTIVE로 실행할 수 있습니다.
Adding both spring-boot-starter-web and spring-boot-starter-webflux modules in your application results in Spring Boot auto-configuring Spring MVC, not WebFlux. This behavior has been chosen because many Spring developers add spring-boot-starter-webflux to their Spring MVC application to use the reactive WebClient. You can still enforce your choice by setting the chosen application type to SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE).
참조: https://docs.spring.io/spring-boot/docs/current/reference/html/web.html#web.reactive.webflux
Spring Cloud Gateway의 의존성
WebApplicationType
는 알겠고 그럼 왜 Spring Cloud Gateway는 WebApplicationType.REACTIVE로써 웹 애플리케이션이 구동이 될까요?
이는 spring-cloud-gateway-server
의존성 내부를 들여다보면 알 수 있습니다. 아래는 spring-cloud-gateway-server-3.0.3.pom
파일의 일부를 발췌한 내용입니다.
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gateway</artifactId>
<version>3.0.3</version>
<relativePath>..</relativePath>
</parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gateway-server</artifactId>
<version>3.0.3</version>
<name>Spring Cloud Gateway Server</name>
<description>Spring Cloud Gateway Server</description>
<url>https://spring.io/spring-cloud/spring-cloud-gateway/spring-cloud-gateway-server</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>https://www.spring.io</url>
</organization>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
</license>
</licenses>
...
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>2.4.6</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
...
</dependencies>
</project>
<dependencies>
태그 내에 spring-boot-starter-webflux
의존성이 확인되시나요? 그렇습니다. Spring WebFlux의 의존성이 존재하기 때문에 REACTIVE로써 구동이 되는 것입니다.
결론
Spring Cloud Gateway가 REACTIVE 타입의 웹 애플리케이션으로써 구동되는 것은 비동기 웹 프로그래밍을 지원하기 위함으로 보여집니다. MSA(Microservices Architecture)에서 비동기 통신을 활용하는 것이 왜 좋은가에 대해서는 아래 안내해드리는 글을 참고하시면 알 수 있습니다.
참고: Spring WebFlux와 Armeria를 이용하여 Microservice에 필요한 Reactive + RPC 동시에 잡기