티스토리 뷰
이번에는 Spring WebMVC와 WebFlux의 의존성이 모두 존재하는 경우에 어떻게 동작하는지 살펴보도록 하겠습니다.
1. WebMVC와 WebFlux 의존성이 모두 존재하는 경우의 동작 방식
[ WebMVC와 WebFlux ]
스프링에는 WebMVC와 WebFlux, 2가지의 웹 프레임워크가 있다.
- WebMVC: 전통적인 멀티 쓰레드 기반의 웹 프레임워크
- WebFlux: 리액티브 스택 기반의 웹 프레임워크
2가지 웹 프레임워크는 다음과 같은 의존성을 추가함으로써 사용 가능하다. 2가지 의존성을 모두 추가하는 것도 가능한데, 이러한 경우에는 어떻게 동작하게 되는지 살펴보도록 하자.
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
[ WebMVC와 WebFlux 의존성이 모두 존재하는 경우 ]
스프링은 애플리케이션 타입을 설정하는데, 3가지를 Enum으로 관리한다. 스프링은 DI 프레임워크인 만큼 웹이 아닌 프로젝트에서도 사용이 가능한데, 이때 NONE 타입이 사용된다.
- NONE: 웹 애플리케이션이 아닌 경우
- SERVLET: 서블릿 웹 애플리케이션인 경우
- REACTIVE: 리액티브 웹 애플리케이션인 경우
애플리케이션이 실행될 때 클래스 패스를 기반으로 애플리케이션 타입을 선택하는데, 해당 로직은 다음과 같다. 리액티브 타입으로 선택되려면 클래스패스에 웹 플럭스 의존성은 존재하고, 서블릿 의존성은 존재하지 않는 경우에만 가능함을 확인할 수 있다. 즉, 2가지 의존성이 모두 존재한다면 서블릿 기반으로 스프링이 실행되는 것이다.
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
[ WebMVC와 WebFlux 자동 설정을 모두 활성화하는 경우 ]
애플리케이션 타입이 정해지면 자동 설정이 진행되는데, 각각 서블릿 기반과 리액티브 기반의 자동 설정을 활성화하는 클래스는 각각 WebMvcAutoConfiguration와 WebFluxAutoConfiguration이다.
@AutoConfiguration(after = { ReactiveWebServerFactoryAutoConfiguration.class, CodecsAutoConfiguration.class,
ReactiveMultipartAutoConfiguration.class, ValidationAutoConfiguration.class,
WebSessionIdResolverAutoConfiguration.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass(WebFluxConfigurer.class)
@ConditionalOnMissingBean({ WebFluxConfigurationSupport.class })
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
public class WebFluxAutoConfiguration {
... 생략
}
WebFluxAutoConfiguration이 활성화되는 조건을 살펴보면 다음과 같다.
- 애플리케이션이 리액티브 타입인 경우
- 클래스패스에 웹플럭스가 존재하는 경우
- WebFluxConfigurationSupport 타입의 빈이 없는 경우
일반적으로 2가지 의존성이 모두 존재하면 애플리케이션 타입이 SERVLET이 되므로 WebFlux 관련 자동 설정은 활성화되지 않는다. 하지만 @EnableWebFlux 어노테이션을 사용하면 WebFluxAutoConfiguration을 강제로 활성화 시킬 수 있다. 이러한 경우에는 2가지 웹 프레임워크 설정이 자동으로 활성화되므로 문제가 발생할 수 있는데, 그래서 WebFluxConfigurationSupport에 applicationCotext을 세팅할 때 WebMVC 자동 설정이 되었다면 assert를 통해 이를 방지하고 있다.
public class WebFluxConfigurationSupport implements ApplicationContextAware {
... 생략
@Override
public void setApplicationContext(@Nullable ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
if (applicationContext != null) {
Assert.state(!applicationContext.containsBean("mvcContentNegotiationManager"),
"The Java/XML config for Spring MVC and Spring WebFlux cannot both be enabled, " +
"e.g. via @EnableWebMvc and @EnableWebFlux, in the same application.");
}
}
... 생략
}
즉, 위에서 살펴본 내용들을 정리하면 WebMVC와 WebFlux 의존성이 모두 존재하면 애플리케이션 타입이 SERVLET으로 설정되고, WebMVC 기반으로 스프링이 실행된다는 것이다. 그리고 @EnableWebFlux 어노테이션으로 WebFlux 설정을 강제 활성화해도, 애플리케이션 실행 시점에 에러를 던져 이러한 상황을 방지하고 있다.
위의 내용들은 개인적으로 공부를 하면서 작성을 한 내용이라 충분히 틀리거나 잘못된 내용들이 있을 수 있습니다. 혹시 수정 또는 추가할 내용들을 발견하셨다면 댓글 남겨주세요! 반영해서 수정하도록 하겠습니다:)