Spring Framework
Spring Webflux - Server Configuration
흥부가귀막혀
2022. 3. 14. 13:06
Server Configuration
@EnableWebFlux
- @EnableWebFlux 어노테이션을 정의할 경우 DelegatingWebFluxConfiguration 이 동작하는데 해당 Configuration 이 수행하는 기능은 다음과 같다.
- WebFlux Application 운영을 위한 default spring configuration 을 정의해준다.
- WebFluxConfigurer 를 정의한 configuration 이 있는지 탐지 및 customizing 된 내용 적용.
@Configuration
@EnableWebFlux
public class WebConfig {
// ...
}
- 만약 @EnableWebFlux 를 사용하지 않고 직접 핸들링 하고 싶다면, DelegatingWebFluxConfiguration 을 직접 정의하는 방법도 있다.
@Configuration
public class WebConfig extends DelegatingWebFluxConfiguration {
// ...
}
WebFluxConfigurer
- WebFlux Server side 에 대해 사용자가 정의할 수 있는 옵션을 제공한다.
- WebFluxConfigurer 가 동작하기 위해서는 @EnableWebFlux 가 어딘가 선언되어 있어야 한다.
- WebFluxConfigurer 에서 지원하는 옵션은 다음과 같다.
- addFormatters(FormatterRegistry registry) : Conversion, formatting 관련 옵션
- Validator getValidator() : 전역 Validator 정의
- configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) : 요청 media type 에 대한 resolver 정의. default 는 accept header 를 체크하지만 필요에 따라 parameter base 의 resolver 정의도 가능하다.
- configureHttpMessageCodecs(ServerCodecConfigurer configurer) : request, response read/write 에 관련된 codec 설정 정의. 요청 파라미터 body 사이즈를 256kb 이상 늘리고 싶다면 WebClient 에서 언급되었던 MaxInMemorySize 설정과 동일하게 설정해준다.
- configureViewResolvers(ViewResolverRegistry registry) : view resolver 를 정의. 상세 설정 방법은 spring doc 참고.
- addResourceHandlers(ResourceHandlerRegistry registry) : static resource 에 대한 handler 정의. 각 케이스별 상세 설정은 spring doc 참고.
- configurePathMatch(PathMatchConfigurer configurer) : path matching 에 대한 사용자 옵션을 정의. 옵션에 대한 자세한 사항은 PathMatchConfigurer 참고
- addCorsMappings(CorsRegistry registry) : Cors 에 대한 전역 설정 정의.
- getWebSocketService() : WebSocket Handling 을 위한 WebSocketService 를 정의.
CORS
- WebFluxConfigurer 의 addCorsMappings 을 설정하거나 CorsFilter 를 bean 으로 정의하면 전역 CORS 지원이 가능하다.
WebFluxConfigurer 설정
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(true).maxAge(3600);
// Add more mappings...
}
}
CorsFilter 설정
@Bean
CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// Possibly...
// config.applyPermitDefaultValues()
config.setAllowCredentials(true);
config.addAllowedOrigin("https://domain1.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
CORS 에 대한 custom 한 동작이 필요하다면 CorsConfiguration 를 구현하면 된다. 예를들어 domain 의 allow origin check 를 ant pattern 이나 정규표현식 방식으로 check 하고 싶다면 CorsConfiguration 의 checkOrigin 을 구현하면 된다.
Netty TcpServer
- NettyServerCustomizer 를 구현하여 Netty TcpServer 에 대한 옵션 정의가 가능하다.
- TcpServer 에 설정가능한 옵션은 다음과 같다.(옵션 종류는 ChannelOption 에 필드로 정의되어있다.)
- SO_BACKLOG
- SO_KEEPALIVE
- SO_REUSEADDR
- SO_LINGER
- SO_RCVBUF
- SO_SNDBUF
- SO_TIMEOUT
- TCP_NODELAY
- TcpServer 에 대한 metric 을 활성화 하고 싶다면, TcpServer.metrics(boolean) 함수를 호출하면 된다.
public class EventLoopNettyCustomizer implements NettyServerCustomizer {
@Override
public HttpServer apply(HttpServer httpServer) {
EventLoopGroup parentGroup = new NioEventLoopGroup();
EventLoopGroup childGroup = new NioEventLoopGroup();
return httpServer.tcpConfiguration(tcpServer -> { // 필요한 설정 변경 수행 });
}
}
⚠️ Reactor Netty 의 selector, worker thread 수도 NettyServerCustomizer 를 통해 설정할 수 있는것 같지만, 실제로 해보면 적용이 안된다.
그 이유는 selector, worker thread 는 http server 를 생성할 때 정의해야 하는데 실제 http server 를 생성하는 NettyReactiveWebServerFactory 에서 http server 를 생성한 뒤에 customizer 를 호출하도록 되어있기 때문에 여기서 설정을 해봤자 변경되지 않는다.
selector, worker thread 를 변경하기 위해선 NettyReactiveWebServerFactory 를 통해 ReactorResourceFactory 를 정의해 loopResources 를 셋팅해주거나 ReactorNetty 에 정의된 환경변수를 application 실행시 정의해주어야 한다.
- NettyServerCustomizer 구현체를 Bean 으로 등록하거나 NettyReactiveWebServerFactory 을 Bean 으로 등록하고 이때 NettyServerCustomizer 를 등록하면 된다.
@Configuration
@EnableWebFlux
public class WebConfig {
@Bean
public EventLoopNettyCustomizer eventLoopNettyCustomizer() {
return new EventLoopNettyCustomizer();
}
}
@Configuration
@EnableWebFlux
public class WebConfig {
@Bean
public NettyReactiveWebServerFactory nettyReactiveWebServerFactory() {
NettyReactiveWebServerFactory webServerFactory = new NettyReactiveWebServerFactory();
webServerFactory.addServerCustomizers(new EventLoopNettyCustomizer());
return webServerFactory;
}
}
- SSL, Http2 와 관련된 설정을 하고자 한다면, WebServerFactoryCustomizer 를 직접 정의하면 된다.
@Component
public class NettyWebServerFactorySslCustomizer
implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
@Override
public void customize(NettyReactiveWebServerFactory serverFactory) {
Ssl ssl = new Ssl();
ssl.setEnabled(true);
ssl.setKeyStore("classpath:sample.jks");
ssl.setKeyAlias("alias");
ssl.setKeyPassword("password");
ssl.setKeyStorePassword("secret");
Http2 http2 = new Http2();
http2.setEnabled(false);
serverFactory.addServerCustomizers(new SslServerCustomizer(ssl, http2, null));
serverFactory.setPort(8443);
}
}