Spring Web Reactive | 1. Spring WebFlux | 1.11. WebFlux Config

Web MVC

WebFlux Java 구성은 어노테이션이 선언된 컨트롤러 또는 함수 엔드포인트로 요청을 처리하는데 필요한 컴포넌트를 선언하고 구성을 정의하는 API를 제공한다. 즉, Java 구성 의해 작성된 기본 Bean을 이해할 필요는 없다. 그래도 더 이해하고 싶다면, WebFluxConfigurationSupport을 보거나, 특별한 Bean 유형의 내용에 대한 자세한 내용 읽어 봐라.

구성 API에는 없는 고급 사용자 지정 내용은 고급 구성 모드를 사용하여 구성을 완전히 제어 할 수 있다.

1.11.1. WebFlux 구성 활성화

Web MVC

다음의 예와 같이, Java config에 @EnableWebFlux 어노테이션을 사용할 수 있다.

Java

@Configuration
@EnableWebFlux
public class WebConfig {
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig

위의 예에서는 다수의 Spring WebFlux 인프라스트럭처 Bean(infrastructure beans)을 등록하고 JSON, XML 등과 같이 클래스 경로에 사용할 수 있는 종속성에 적용한다.

1.11.2. WebFlux 구성 API

Web MVC

Java 구성은 다음 예제와 같이 WebFluxConfigurer 인터페이스를 구현할 수 있다.

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    // Implement configuration methods...
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    // Implement configuration methods...
}

1.11.3. 변환, 포맷(Conversion, formatting)

Web MVC

디폴트로 다양한 숫자 및 날짜 형식의 포맷터(formatters)를 제공하고, @NumberFormat@DateTimeFormat을 선언하 사용자가 정의한 포맷터를 지정할 수도 있다.

Java config에서 사용자 정의 포맷터와 변환기를 등록하려면 다음과 같이 한다.

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        // ...
    }

}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun addFormatters(registry: FormatterRegistry) {
        // ...
    }
}

기본적으로 Spring WebFlux는 날짜 값을 파싱 및 포맷팅을 할 때, 요청 로케일을 고려한다. 이 날짜가 “입력” 양식 필드를 가진 문자열로 표현 양식으로 작동한다. 그러나 “날짜"와 “시간” 양식 필드의 경우 브라우저는 HTML 명세에 정의되어 있는 고정 형식을 사용한다. 이런 경우, 날짜 및 시간 형식은 다음과 같이 정의 할 수 있다.

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
        registrar.setUseIsoFormat(true);
        registrar.registerFormatters(registry);
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun addFormatters(registry: FormatterRegistry) {
        val registrar = DateTimeFormatterRegistrar()
        registrar.setUseIsoFormat(true)
        registrar.registerFormatters(registry)
    }
}

FormatterRegistrar 구현을 언제 사용하는지에 대한 자세한 내용은 FormatterRegistrar SPIFormattingConversionServiceFactoryBean 참조해라.

1.11.4. 검증(Validation)

Web MVC

기본적으로 Bean 검증이 클래스 패스에 존재하는 경우(Hibernate Validator 등), LocalValidatorFactoryBean@Controller 메소드 인수의 @Valid@Validated으로 사용하기 위한 글로벌 Validator로 등록된다.

Java 구성은 다음 예와 같이 글로벌 Validator 인스턴스를 지정할 수 있다.

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public Validator getValidator(); {
        // ...
    }

}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun getValidator(): Validator {
        // ...
    }

}

다음의 예와 같이, Validator 구현을 로컬로 등록 할 수 있다.

Java

@Controller
public class MyController {

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.addValidators(new FooValidator());
    }

}

Kotlin

@Controller
class MyController {

    @InitBinder
    protected fun initBinder(binder: WebDataBinder) {
        binder.addValidators(FooValidator())
    }
}

LocalValidatorFactoryBean를 어딘가에 삽입해야 하는 경우는 Bean을 작성하고 @Primary을 선언하여, MVC config에서 선언된 것과 충돌을 방지한다.

1.11.5. 콘텐츠 타입 리졸버(Content Type Resolvers)

Web MVC

Spring WebFlux는 요청으로 부터 @Controller 인스턴스 요청된 미디어 타입을 결정하는 방법을 설정할 수 있다. 기본적으로 Accept 헤더만 체크되지만, 쿼리 매개 변수 기반으로 하도록 활성화 할 수 있다.

다음의 예는 요청된 콘텐츠 타입 리솔루션을 사용자 지정하는 방법을 보여준다.

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
        // ...
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureContentTypeResolver(builder: RequestedContentTypeResolverBuilder) {
        // ...
    }
}

1.11.6. HTTP 메시지 코덱

Web MVC

다음 예제는 요청 및 응답 본문 읽기 및 쓰기 방법을 사용자 지정하는 방법을 보여준다.

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
        configurer.defaultCodecs().maxInMemorySize(512 * 1024);
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
        // ...
    }
}

ServerCodecConfigurer는 디폴트 reader와 writer 세트를 제공한다. 이것을 사용하여 reader와 writer를 추가하거나 디폴트을 정의하고 디폴트을 완전히 대체 할 수 있다.

Jackson JSON와 XML의 경우 Jackson2ObjectMapperBuilder의 사용을 고려하자. Jackson2ObjectMapperBuilder는 Jackson의 기본 속성을 다음과 같이 정의한다.

또한, 다음 알려진 모듈이 클래스 경로에서 감지 된 경우 자동으로 등록한다.

1.11.7. 뷰 리졸버(View Resolvers)

Web MVC

다음의 예는 뷰 리졸버을 구성하는 방법을 보여준다.

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        // ...
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        // ...
    }
}

ViewResolverRegistry은 Spring Framework가 통합된 뷰 기술에 대한 간단한 등록 방법을 제공한다. 다음 예제에서는 FreeMarker를 사용하고 있다(여기에는 기본 FreeMarker 뷰 기술의 구성도 필요하다)

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {


    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.freeMarker();
    }

    // Configure Freemarker...

    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() {
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        configurer.setTemplateLoaderPath("classpath:/templates");
        return configurer;
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.freeMarker()
    }

    // Configure Freemarker...

    @Bean
    fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
        setTemplateLoaderPath("classpath:/templates")
    }
}

다음의 예와 같이, ViewResolver 구현을 등록 할 수 있다.

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {


    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        ViewResolver resolver = ... ;
        registry.viewResolver(resolver);
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        val resolver: ViewResolver = ...
        registry.viewResolver(resolver
    }
}

컨텐츠 협상(Content Negotiation)을 지원하고 뷰 리졸버(HTML 이외)을 통해 다른 형식을 렌더링하려면 spring-web에서 사용 가능한 코덱 중 하나를 받아들이는 HttpMessageWriterView 구현에 따라 하나 이상의 기본 뷰를 구성 할 수 있다. 다음의 예는 그 방법을 보여준다.

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {


    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.freeMarker();

        Jackson2JsonEncoder encoder = new Jackson2JsonEncoder();
        registry.defaultViews(new HttpMessageWriterView(encoder));
    }

    // ...
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {


    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.freeMarker()

        val encoder = Jackson2JsonEncoder()
        registry.defaultViews(HttpMessageWriterView(encoder))
    }

    // ...
}

Spring WebFlux와 통합된 뷰 기술에 대한 자세한 내용은 뷰 기술을 참조해라.

1.11.8. 정적 리소스(Static Resources)

Web MVC

이 옵션은 Resource 기반 위치 목록에서 정적 리소스를 제공하기 위한 편리한 방법을 제공한다.

다음 예제에서는 /resources로 시작하는 요청을 지정하면, 상대 경로를 사용하여 클래스 경로의 /static에 관련된 정적 자원을 찾아 처리한다. 브라우저의 캐시를 최대한 사용하고, 브라우저가 수행하는 HTTP 요청을 줄이기 위해, 자원에는 1년간의 유지 기간이 설정하고 있다. Last-Modified 헤더가 있는 경우에 그 값을 평가하고 304 상태 코드가 반환된다.

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
            .addResourceLocations("/public", "classpath:/static/")
            .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS));
    }

}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public", "classpath:/static/")
                .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
    }
}

리소스 핸들러는 ResourceResolver 구현, ResourceTransformer 구현의 체인도 지원하고 있다. 이것들을 사용하여 최적화된 리소스를 조작하기 위한 툴 체인을 만들 수 있다.

콘텐츠, 고정 응용 프로그램 버전 또는 기타 정보에서 계산된 MD5 해시를 기반으로 버전 관리된 리소스 URL에 VersionResourceResolver을 사용할 수 있다. ContentVersionStrategy(MD5 해시)은 몇 가지 주의해야 할 예외(모듈 로더에서 사용된 JavaScript 자원 등)이 있는 경우에 적합하다.

다음의 예제는 Java 구성에 VersionResourceResolver을 사용하는 방법을 보여준다.

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public/")
                .resourceChain(true)
                .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
    }

}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public/")
                .resourceChain(true)
                .addResolver(VersionResourceResolver().addContentVersionStrategy("/**"))
    }

}

ResourceUrlProvider 를 사용하여 URL을 다시 쓰고, 리졸뷰와 트랜스포머의 전체 체인을 적용 할 수 있다(예를 들어, 버전을 삽입하기 위해). WebFlux 구성은 ResourceUrlProvider 을 제공하기 위해, 다른 주입할 수 있다.

Spring MVC와 달리 현재 WebFlux는 리졸뷰와 트랜스포머의 논블로킹 체인을 사용할 수 있는 뷰 기술이 없기 때문에, 정적 리소스 URL을 투명하게 바꾸는 방법은 없다. 로컬 자원만을 제공하는 경우 해결 방법은 ResourceUrlProvider를 직접 (예를 들어, 사용자 지정 요소를 통해) 사용하여 블로킹하는 것이다.

EncodedResourceResolver(예를 들어, Gzip, Brotli 인코딩)와 VersionedResourceResolver 모두를 사용하는 경우, 인코딩되지 않은 파일에 따라 콘텐츠 기반 버전이 항상 안정적으로 계산되도록 이 순서로 등록해야 한다.

WebJarsorg.webjars:webjars-locator-core 라이브러리가 클래스 경로에 존재할 때 자동으로 등록되는 WebJarsResourceResolver에도 지원된다. 리졸뷰는 jar 버전을 포함하는 URL을 다시 쓸때, 버전 없는 수신 URL(예를 들어, /jquery/jquery.min.js에서 /jquery/1.2.0/jquery.min.js 등)과 조합 할 수도 있다.

1.11.9. 경로 매칭

Web MVC

경로 매칭에 대한 옵션을 설정할 수 있다. 개별 옵션에 대한 자세한 내용은 PathMatchConfigurer javadoc를 참조해라. 다음 예제는 PathMatchConfigurer의 사용 방법을 보여준다.

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer
            .setUseCaseSensitiveMatch(true)
            .setUseTrailingSlashMatch(false)
            .addPathPrefix("/api",
                    HandlerTypePredicate.forAnnotation(RestController.class));
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    @Override
    fun configurePathMatch(configurer: PathMatchConfigurer) {
        configurer
            .setUseCaseSensitiveMatch(true)
            .setUseTrailingSlashMatch(false)
            .addPathPrefix("/api",
                    HandlerTypePredicate.forAnnotation(RestController::class.java))
    }
}

Spring WebFlux는 디코딩 된 경로 세그먼트 값에 액세스하기 위해 RequestPath 라는 요청 경로 분석 된 표현에 따라 세미콜론 콘텐츠 (즉, 경로 또는 행렬 변수)를 제거한다. 즉, Spring MVC와 달리 요청 경로를 디코딩하거나 경로 일치를 위해 세미콜론 콘텐츠를 삭제할지 여부를 지정할 필요가 없다.

Spring WebFlux 또한 또한되는 Spring MVC, 그리고 달리 접미사 패턴 매칭을 지원하지 않는 것이 좋습니다 , 그것은 멀리 의존에서 이동한다.

1.11.10. WebSocketService

WebFlux Java 구성은 WebSocket 핸들러의 호출을 지원하는 WebSocketHandlerAdapter Bean을 선언한다. 즉, WebSocket 핸드 셰이크 요청을 처리하기 위해 필요한 것은WebSocketHandlerSimpleUrlHandlerMapping를 통해 URL에 매핑 할뿐이다.

경우에 따라서는 WebSocket 서버의 속성을 구성 할 수 있는 WebSocketService 서비스를 제공하고 WebSocketHandlerAdapter Bean을 작성해야 한다. 예를 들면, 아래와 같다.

Java

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public WebSocketService getWebSocketService() {
        TomcatRequestUpgradeStrategy strategy = new TomcatRequestUpgradeStrategy();
        strategy.setMaxSessionIdleTimeout(0L);
        return new HandshakeWebSocketService(strategy);
    }
}

Kotlin

@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    @Override
    fun webSocketService(): WebSocketService {
        val strategy = TomcatRequestUpgradeStrategy().apply {
            setMaxSessionIdleTimeout(0L)
        }
        return HandshakeWebSocketService(strategy)
    }
}

1.11.11. 고급 설정 모드(Advanced Configuration Mode)

Web MVC

@EnableWebFluxDelegatingWebFluxConfiguration 을 가져온다 :

  • WebFlux 응용 프로그램에 디폴트로 Spring 설정을 제공한다.
  • WebFluxConfigurer 구현을 감지하여 위임하고 그 구성을 사용자 정의한다.

고급 설정 모드의 경우, 다음의 예와 같이, WebFluxConfigurer 구현하는 대신에 @EnableWebFlux 을 제거하고 DelegatingWebFluxConfiguration을 직접 확장할 수 있다.

Java

@Configuration
public class WebConfig extends DelegatingWebFluxConfiguration {

    // ...
}

Kotlin

@Configuration
class WebConfig : DelegatingWebFluxConfiguration {

    // ...
}

기존의 메소드를 WebConfig에 보유 할 수 있지만, 기본 클래스에서 Bean 선언을 오버라이딩할 수 있고, 클래스 경로에 다른 WebMvcConfigurer 구현을 얼마든지 할 수 있다.




최종 수정 : 2021-04-12