CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework--spring-webflux

Spring WebFlux reactive web framework for building non-blocking, reactive web applications

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

Spring WebFlux

Spring WebFlux is a reactive-stack web framework for building non-blocking, reactive web applications with Reactive Streams back pressure.

Package Information

  • Maven Coordinates: org.springframework:spring-webflux:7.0.1
  • Language: Java
  • Requires: Spring Framework 7.0.1+, Reactor Core 3.6+

Installation:

Maven:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webflux</artifactId>
    <version>7.0.1</version>
</dependency>

Gradle:

implementation 'org.springframework:spring-webflux:7.0.1'

Quick Start

Minimal Annotation Controller

import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping("/api")
public class ApiController {

    @GetMapping("/hello")
    public Mono<String> hello() {
        return Mono.just("Hello, WebFlux!");
    }

    @PostMapping("/users")
    public Mono<User> createUser(@RequestBody User user) {
        return userRepository.save(user);
    }
}

Minimal Functional Route

import org.springframework.context.annotation.Bean;
import org.springframework.web.reactive.function.server.*;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.RequestPredicates.*;

@Bean
public RouterFunction<ServerResponse> routes() {
    return route(GET("/hello"),
        request -> ServerResponse.ok().bodyValue("Hello, WebFlux!"));
}

Minimal WebClient Call

import org.springframework.web.reactive.function.client.WebClient;

WebClient client = WebClient.create("https://api.example.com");
Mono<User> user = client.get()
    .uri("/users/{id}", userId)
    .retrieve()
    .bodyToMono(User.class);

Core Imports

// Annotations
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.config.EnableWebFlux;

// Functional Routing
import org.springframework.web.reactive.function.server.*;
import static org.springframework.web.reactive.function.server.RouterFunctions.*;
import static org.springframework.web.reactive.function.server.RequestPredicates.*;

// WebClient
import org.springframework.web.reactive.function.client.WebClient;

// Reactive Types
import reactor.core.publisher.Mono;
import reactor.core.publisher.Flux;

// Exception Handling
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.server.ResponseStatusException;

// WebSocket
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketSession;
import org.springframework.web.reactive.socket.WebSocketMessage;

Architecture Overview

Two Programming Models:

  1. Annotation Controllers: @RestController, @RequestMapping, method annotations
  2. Functional Endpoints: RouterFunction, HandlerFunction, composable routes

Request Processing Flow:

Request → DispatcherHandler → HandlerMapping → HandlerAdapter → Handler → Result Handler → Response

Core Components:

  • DispatcherHandler: Central request dispatcher
  • HandlerMapping: Routes requests to handlers
  • HandlerAdapter: Invokes handlers, processes arguments/return values
  • HandlerResultHandler: Writes handler results to response

Reactive Foundation:

  • Built on Project Reactor (Mono<T> for 0-1 items, Flux<T> for 0-N items)
  • Non-blocking, backpressure-aware
  • Event loop concurrency model

Server Support: Netty (default), Tomcat, Jetty, Undertow, Servlet 3.1+

Feature Overview

1. Configuration → Details

Configure WebFlux using @EnableWebFlux and WebFluxConfigurer:

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("https://example.com");
    }
}

Key Configuration Areas:

  • HTTP message codecs, formatters, validation
  • CORS, path matching, content type resolution
  • View resolvers, resource handlers
  • API versioning, blocking execution

2. WebClient → Details

Non-blocking HTTP client with fluent API:

WebClient client = WebClient.builder()
    .baseUrl("https://api.example.com")
    .defaultHeader("Authorization", "Bearer " + token)
    .build();

// GET request
Mono<User> user = client.get()
    .uri("/users/{id}", id)
    .retrieve()
    .bodyToMono(User.class);

// POST request with error handling
Mono<Response> response = client.post()
    .uri("/users")
    .bodyValue(newUser)
    .retrieve()
    .onStatus(HttpStatusCode::is4xxClientError,
        res -> Mono.error(new ClientException()))
    .bodyToMono(Response.class);

Features: Request/response filtering, timeout, retry, error handling, streaming

3. Functional Routing → Details

Composable, functional route definitions:

@Bean
public RouterFunction<ServerResponse> routes(UserHandler handler) {
    return route()
        .GET("/users/{id}", handler::getUser)
        .GET("/users", handler::listUsers)
        .POST("/users", handler::createUser)
        .filter((request, next) -> {
            // Logging, auth, etc.
            return next.handle(request);
        })
        .build();
}

Key Types: RouterFunction, HandlerFunction, ServerRequest, ServerResponse, RequestPredicate

4. Annotation Controllers → Details

Familiar Spring MVC-style controllers with reactive types:

@RestController
@RequestMapping("/users")
public class UserController {

    @GetMapping("/{id}")
    public Mono<User> getUser(@PathVariable String id) {
        return userService.findById(id);
    }

    @PostMapping
    public Mono<User> createUser(@RequestBody @Valid User user) {
        return userService.save(user);
    }
}

Method Arguments: @PathVariable, @RequestParam, @RequestBody, @RequestHeader, @CookieValue, ServerWebExchange, Principal, reactive types

Return Types: Mono<T>, Flux<T>, ResponseEntity, Rendering, void, plain objects

5. WebSocket → Details

Bidirectional real-time communication:

public class ChatHandler implements WebSocketHandler {
    @Override
    public Mono<Void> handle(WebSocketSession session) {
        return session.send(
            session.receive()
                .map(msg -> session.textMessage("Echo: " + msg.getPayloadAsText()))
        );
    }
}

Features: Text/binary messages, ping/pong, handshake info, sub-protocols, multiple server implementations

6. Resource Handling → Details

Serve static resources with caching, versioning, transformation:

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

Features: Version strategies (content hash, fixed), gzip/brotli encoding, CSS link transformation, WebJars support

7. View Rendering → Details

Server-side template rendering:

@GetMapping("/users")
public Mono<Rendering> listUsers() {
    return userService.findAll()
        .collectList()
        .map(users -> Rendering.view("userList")
            .modelAttribute("users", users)
            .build());
}

Supported: FreeMarker, script templates (Nashorn, GraalVM JS), custom views

8. Content Negotiation & API Versioning → Details

Resolve content types and API versions:

@Override
public void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
    builder.headerResolver()
        .parameterResolver("format")
        .mediaType("json", MediaType.APPLICATION_JSON)
        .mediaType("xml", MediaType.APPLICATION_XML);
}

@Override
public void configureApiVersioning(ApiVersionConfigurer configurer) {
    configurer.addVersionResolver(new HeaderApiVersionResolver("API-Version"))
        .setVersionStrategy(new DefaultApiVersionStrategy()
            .addVersions("1.0", "2.0", "3.0")
            .addDeprecatedVersions("1.0"));
}

Version Resolution: Header, query parameter, path segment, media type parameter

9. Exception Handling → Details

Handle exceptions globally or per-controller:

@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(NotFoundException.class)
    public Mono<ResponseEntity<ErrorResponse>> handleNotFound(NotFoundException ex) {
        return Mono.just(ResponseEntity.status(404)
            .body(new ErrorResponse("NOT_FOUND", ex.getMessage())));
    }
}

Approaches: @ExceptionHandler, ResponseEntityExceptionHandler, @ResponseStatus, functional onError(), DispatchExceptionHandler

Common Integration Patterns

REST API with Error Handling

@RestController
@RequestMapping("/api/users")
public class UserApiController {

    private final UserService userService;

    @GetMapping("/{id}")
    public Mono<ResponseEntity<User>> getUser(@PathVariable String id) {
        return userService.findById(id)
            .map(ResponseEntity::ok)
            .defaultIfEmpty(ResponseEntity.notFound().build());
    }

    @PostMapping
    public Mono<ResponseEntity<User>> createUser(@RequestBody @Valid User user) {
        return userService.save(user)
            .map(saved -> ResponseEntity
                .created(URI.create("/api/users/" + saved.getId()))
                .body(saved));
    }

    @ExceptionHandler(ValidationException.class)
    public ResponseEntity<ErrorResponse> handleValidation(ValidationException ex) {
        return ResponseEntity.badRequest()
            .body(new ErrorResponse("VALIDATION_ERROR", ex.getMessage()));
    }
}

Streaming Data with Backpressure

@GetMapping(value = "/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<Event>> streamEvents() {
    return eventService.subscribeToEvents()
        .map(event -> ServerSentEvent.builder(event)
            .id(event.getId())
            .event("message")
            .build())
        .onBackpressureBuffer(100);
}

File Upload with Multipart

@PostMapping("/upload")
public Mono<String> handleUpload(@RequestPart("file") FilePart file,
                                 @RequestPart("metadata") Metadata metadata) {
    return file.transferTo(Path.of("/uploads/" + file.filename()))
        .then(Mono.just("Upload successful"));
}

Authentication with WebFilter

@Bean
public WebFilter authenticationFilter() {
    return (exchange, chain) -> {
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (token == null || !isValid(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange)
            .contextWrite(Context.of("userId", extractUserId(token)));
    };
}

Core Types Reference

Request/Response Types

public interface ServerWebExchange {
    ServerHttpRequest getRequest();
    ServerHttpResponse getResponse();
    Mono<WebSession> getSession();
    Mono<? extends Principal> getPrincipal();
    Map<String, Object> getAttributes();
}

public class ServerHttpRequest extends HttpRequest {
    URI getURI();
    HttpHeaders getHeaders();
    MultiValueMap<String, HttpCookie> getCookies();
    Flux<DataBuffer> getBody();
}

public class ServerHttpResponse extends HttpResponse {
    void setStatusCode(HttpStatus status);
    HttpHeaders getHeaders();
    Mono<Void> writeWith(Publisher<? extends DataBuffer> body);
}

Handler Types

public interface WebHandler {
    Mono<Void> handle(ServerWebExchange exchange);
}

public class DispatcherHandler implements WebHandler {
    // Central dispatcher - delegates to HandlerMapping → HandlerAdapter
}

public interface HandlerMapping {
    Mono<Object> getHandler(ServerWebExchange exchange);
}

public interface HandlerAdapter {
    boolean supports(Object handler);
    Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler);
}

public class HandlerResult {
    Object getHandler();
    Object getReturnValue();
    MethodParameter getReturnType();
    BindingContext getBindingContext();
}

Configuration Types

@Target(ElementType.TYPE)
@Import(DelegatingWebFluxConfiguration.class)
public @interface EnableWebFlux { }

public interface WebFluxConfigurer {
    void configureHttpMessageCodecs(ServerCodecConfigurer configurer);
    void addFormatters(FormatterRegistry registry);
    void addCorsMappings(CorsRegistry registry);
    void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder);
    void configureApiVersioning(ApiVersionConfigurer configurer);
    void configurePathMatching(PathMatchConfigurer configurer);
    void configureViewResolvers(ViewResolverRegistry registry);
    void addResourceHandlers(ResourceHandlerRegistry registry);
    void configureBlockingExecution(BlockingExecutionConfigurer configurer);
}

Thread Safety & Concurrency

Thread Safety:

  • All WebFlux handlers execute on event loop threads (small thread pool)
  • Do NOT block event loop threads - use subscribeOn() or publishOn() for blocking operations
  • ServerWebExchange is NOT thread-safe - do not share across threads
  • Reactive operators are thread-safe and immutable

Blocking Operations:

// WRONG - blocks event loop
@GetMapping("/users")
public Mono<User> getUser() {
    User user = blockingJdbcCall(); // BAD!
    return Mono.just(user);
}

// CORRECT - offload blocking work
@GetMapping("/users")
public Mono<User> getUser() {
    return Mono.fromCallable(() -> blockingJdbcCall())
        .subscribeOn(Schedulers.boundedElastic());
}

Configure Blocking Scheduler:

@Override
public void configureBlockingExecution(BlockingExecutionConfigurer configurer) {
    configurer.setExecutor(Schedulers.boundedElastic());
}

Error Handling Patterns

Reactive Error Operators:

  • onErrorReturn(fallbackValue) - return default value on error
  • onErrorResume(fallbackPublisher) - switch to fallback publisher
  • onErrorMap(mapper) - transform error
  • onErrorContinue((error, value) -> ...) - log and continue
  • retry(n) - retry on error
  • timeout(duration) - fail if no emission within duration
return webClient.get()
    .uri("/data")
    .retrieve()
    .bodyToMono(Data.class)
    .timeout(Duration.ofSeconds(5))
    .retry(3)
    .onErrorResume(TimeoutException.class, e ->
        Mono.just(new Data("cached")))
    .onErrorMap(WebClientException.class, e ->
        new ServiceException("Failed to fetch data", e));

Performance Considerations

Backpressure: WebFlux automatically handles backpressure - slow consumers signal upstream to slow down production

Memory:

  • Default max in-memory buffer: 256KB per request
  • Configure via ServerCodecConfigurer.defaultCodecs().maxInMemorySize()
  • Large payloads: Use streaming (Flux<DataBuffer>) instead of loading into memory

Connection Pooling:

HttpClient httpClient = HttpClient.create()
    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
    .responseTimeout(Duration.ofSeconds(5))
    .option(ChannelOption.SO_KEEPALIVE, true);

WebClient client = WebClient.builder()
    .clientConnector(new ReactorClientHttpConnector(httpClient))
    .build();

Common Pitfalls

  1. Blocking Calls: Never block event loop threads - use subscribeOn(Schedulers.boundedElastic())
  2. Not Subscribing: Mono/Flux are lazy - nothing happens until subscribed (framework subscribes for controller return values)
  3. Dropping Errors: Always handle errors with onErrorResume() or let them propagate
  4. Memory Leaks: Release DataBuffer instances or use try-with-resources
  5. Incorrect Threading: Don't use ThreadLocal - use Reactor Context instead
  6. Blocking in Filters: WebFilter.filter() must return quickly - offload blocking work
  7. Large Request Bodies: Configure maxInMemorySize for large uploads
  8. Connection Leaks: Always consume response body completely or cancel

Additional Resources

  • Documentation: https://docs.spring.io/spring-framework/reference/web/webflux.html
  • Project Reactor: https://projectreactor.io/docs/core/release/reference/
  • Reactive Streams Spec: https://www.reactive-streams.org/
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/org.springframework/spring-webflux@7.0.x
Publish Source
CLI
Badge
tessl/maven-org-springframework--spring-webflux badge