or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdfunctional-programming.mdhttp-client.mdindex.mdrequest-processing.mdview-resolution.mdwebsocket.md

request-processing.mddocs/

0

# Request Processing Pipeline

1

2

The Spring WebFlux request processing pipeline consists of core framework components that handle request dispatching, handler mapping, adaptation, and result processing in reactive web applications. This infrastructure provides the foundation for both annotation-based and functional programming models.

3

4

## Capabilities

5

6

### Dispatcher Handler

7

8

Central dispatcher for HTTP request handlers and controllers in reactive web applications, similar to Spring MVC's DispatcherServlet.

9

10

```java { .api }

11

class DispatcherHandler implements WebHandler, PreFlightRequestHandler, ApplicationContextAware {

12

/**

13

* Create a new DispatcherHandler which needs to be configured with an ApplicationContext.

14

*/

15

DispatcherHandler();

16

17

/**

18

* Create a new DispatcherHandler for the given ApplicationContext.

19

* @param applicationContext the application context

20

*/

21

DispatcherHandler(ApplicationContext applicationContext);

22

23

/**

24

* Handle the web server exchange.

25

* @param exchange the current server exchange

26

* @return completion signal

27

*/

28

@Override

29

Mono<Void> handle(ServerWebExchange exchange);

30

31

/**

32

* Return the configured HandlerMapping beans.

33

* @return list of handler mappings

34

*/

35

List<HandlerMapping> getHandlerMappings();

36

37

/**

38

* Handle a CORS pre-flight request.

39

* @param exchange the current server exchange

40

* @return completion signal

41

*/

42

@Override

43

Mono<Void> handlePreFlight(ServerWebExchange exchange);

44

}

45

```

46

47

**Usage Examples:**

48

49

```java

50

// Configure DispatcherHandler as main WebHandler

51

@Configuration

52

public class WebFluxConfig {

53

54

@Bean

55

public DispatcherHandler dispatcherHandler(ApplicationContext context) {

56

return new DispatcherHandler(context);

57

}

58

59

// Or use auto-configuration with @EnableWebFlux

60

@Bean

61

public RouterFunction<ServerResponse> routes() {

62

return RouterFunctions.route()

63

.GET("/api/health", request -> ServerResponse.ok().bodyValue("OK"))

64

.build();

65

}

66

}

67

68

// Custom WebHandler that delegates to DispatcherHandler

69

@Component

70

public class CustomWebHandler implements WebHandler {

71

72

private final DispatcherHandler dispatcherHandler;

73

74

public CustomWebHandler(DispatcherHandler dispatcherHandler) {

75

this.dispatcherHandler = dispatcherHandler;

76

}

77

78

@Override

79

public Mono<Void> handle(ServerWebExchange exchange) {

80

// Pre-processing

81

exchange.getAttributes().put("startTime", System.currentTimeMillis());

82

83

return dispatcherHandler.handle(exchange)

84

.doFinally(signal -> {

85

long duration = System.currentTimeMillis() -

86

(Long) exchange.getAttributes().get("startTime");

87

logger.info("Request processed in {}ms", duration);

88

});

89

}

90

}

91

```

92

93

### Handler Mapping

94

95

Interface for mapping requests to handler objects with support for path variables and request attributes.

96

97

```java { .api }

98

interface HandlerMapping {

99

/**

100

* Return a handler for this request.

101

* @param exchange the current exchange

102

* @return a handler instance, or an empty Mono if none found

103

*/

104

Mono<Object> getHandler(ServerWebExchange exchange);

105

106

// Constants for request attributes

107

String BEST_MATCHING_HANDLER_ATTRIBUTE = "bestMatchingHandler";

108

String BEST_MATCHING_PATTERN_ATTRIBUTE = "bestMatchingPattern";

109

String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = "pathWithinHandlerMapping";

110

String URI_TEMPLATE_VARIABLES_ATTRIBUTE = "uriTemplateVariables";

111

String MATRIX_VARIABLES_ATTRIBUTE = "matrixVariables";

112

String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = "producibleMediaTypes";

113

}

114

```

115

116

**Usage Examples:**

117

118

```java

119

// Custom handler mapping

120

@Component

121

public class CustomHandlerMapping implements HandlerMapping {

122

123

private final Map<String, Object> handlers = new HashMap<>();

124

125

public CustomHandlerMapping() {

126

handlers.put("/custom/endpoint", new CustomHandler());

127

}

128

129

@Override

130

public Mono<Object> getHandler(ServerWebExchange exchange) {

131

String path = exchange.getRequest().getPath().value();

132

Object handler = handlers.get(path);

133

134

if (handler != null) {

135

// Set handler mapping attributes

136

exchange.getAttributes().put(

137

BEST_MATCHING_HANDLER_ATTRIBUTE, handler);

138

exchange.getAttributes().put(

139

BEST_MATCHING_PATTERN_ATTRIBUTE, path);

140

141

return Mono.just(handler);

142

}

143

144

return Mono.empty();

145

}

146

}

147

148

// Access handler mapping attributes in handler

149

@RestController

150

public class ExampleController {

151

152

@GetMapping("/users/{id}")

153

public Mono<User> getUser(@PathVariable String id, ServerWebExchange exchange) {

154

// Access URI template variables

155

Map<String, String> pathVars = exchange.getAttribute(

156

HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);

157

158

String userId = pathVars.get("id");

159

return userService.findById(userId);

160

}

161

}

162

```

163

164

### Handler Adapter

165

166

Interface for adapting handler invocation to a common interface, allowing different handler types to be processed uniformly.

167

168

```java { .api }

169

interface HandlerAdapter {

170

/**

171

* Check whether this adapter can handle the given handler instance.

172

* @param handler the handler object to check

173

* @return true if this adapter can adapt the given handler

174

*/

175

boolean supports(Object handler);

176

177

/**

178

* Handle the request with the given handler.

179

* @param exchange the current exchange

180

* @param handler the selected handler

181

* @return the handler result

182

*/

183

Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler);

184

}

185

```

186

187

**Usage Examples:**

188

189

```java

190

// Custom handler adapter for specific handler type

191

@Component

192

public class CustomHandlerAdapter implements HandlerAdapter {

193

194

@Override

195

public boolean supports(Object handler) {

196

return handler instanceof CustomHandler;

197

}

198

199

@Override

200

public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {

201

CustomHandler customHandler = (CustomHandler) handler;

202

203

return customHandler.process(exchange)

204

.map(result -> new HandlerResult(handler, result, null))

205

.doOnError(ex -> logger.error("Handler error", ex));

206

}

207

}

208

209

// Using built-in adapters

210

@Configuration

211

public class WebFluxConfig {

212

213

@Bean

214

public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {

215

RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();

216

adapter.setArgumentResolvers(customArgumentResolvers());

217

adapter.setInitBinderArgumentResolvers(initBinderArgumentResolvers());

218

return adapter;

219

}

220

221

@Bean

222

public HandlerFunctionAdapter handlerFunctionAdapter() {

223

return new HandlerFunctionAdapter();

224

}

225

}

226

```

227

228

### Handler Result

229

230

Class representing the result of handler invocation, containing the handler, return value, and binding context.

231

232

```java { .api }

233

class HandlerResult {

234

/**

235

* Create a new HandlerResult.

236

* @param handler the handler that handled the request

237

* @param returnValue the return value from the handler

238

* @param returnType the return type

239

*/

240

HandlerResult(Object handler, Object returnValue, MethodParameter returnType);

241

242

/**

243

* Create a new HandlerResult with binding context.

244

* @param handler the handler that handled the request

245

* @param returnValue the return value from the handler

246

* @param returnType the return type

247

* @param context the binding context

248

*/

249

HandlerResult(Object handler, Object returnValue, MethodParameter returnType, BindingContext context);

250

251

/**

252

* Return the handler that processed the request.

253

*/

254

Object getHandler();

255

256

/**

257

* Return the return value from the handler.

258

*/

259

Object getReturnValue();

260

261

/**

262

* Return the type of the return value.

263

*/

264

ResolvableType getReturnType();

265

266

/**

267

* Return the MethodParameter for the return type.

268

*/

269

MethodParameter getReturnTypeSource();

270

271

/**

272

* Return the BindingContext used for the request.

273

*/

274

BindingContext getBindingContext();

275

276

/**

277

* Return the model for the request.

278

*/

279

Model getModel();

280

281

/**

282

* Configure exception handling for this result.

283

* @param exceptionHandler the exception handler

284

* @return this HandlerResult for method chaining

285

*/

286

HandlerResult setExceptionHandler(DispatchExceptionHandler exceptionHandler);

287

}

288

```

289

290

**Usage Examples:**

291

292

```java

293

// Create handler result in custom adapter

294

public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {

295

return processHandler(handler, exchange)

296

.map(result -> {

297

MethodParameter returnType = getReturnType(handler);

298

BindingContext context = new BindingContext();

299

300

return new HandlerResult(handler, result, returnType, context);

301

});

302

}

303

304

// Access handler result in result handler

305

@Component

306

public class CustomResultHandler implements HandlerResultHandler {

307

308

@Override

309

public boolean supports(HandlerResult result) {

310

return result.getReturnValue() instanceof CustomResult;

311

}

312

313

@Override

314

public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {

315

CustomResult customResult = (CustomResult) result.getReturnValue();

316

Object handler = result.getHandler();

317

Model model = result.getModel();

318

319

// Process the custom result

320

return writeResponse(exchange, customResult, model);

321

}

322

}

323

```

324

325

### Handler Result Handler

326

327

Interface for processing handler results and writing HTTP responses.

328

329

```java { .api }

330

interface HandlerResultHandler {

331

/**

332

* Check whether this handler can handle the given HandlerResult.

333

* @param result the result object to check

334

* @return true if this handler can handle the result

335

*/

336

boolean supports(HandlerResult result);

337

338

/**

339

* Process the given result and handle the response.

340

* @param exchange the current exchange

341

* @param result the result to handle

342

* @return completion signal

343

*/

344

Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result);

345

}

346

```

347

348

**Usage Examples:**

349

350

```java

351

// Custom result handler for specific return types

352

@Component

353

public class JsonResponseHandler implements HandlerResultHandler {

354

355

private final ObjectMapper objectMapper;

356

357

public JsonResponseHandler(ObjectMapper objectMapper) {

358

this.objectMapper = objectMapper;

359

}

360

361

@Override

362

public boolean supports(HandlerResult result) {

363

Class<?> returnType = result.getReturnType().resolve();

364

return returnType != null &&

365

returnType.isAnnotationPresent(JsonResponse.class);

366

}

367

368

@Override

369

public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {

370

Object returnValue = result.getReturnValue();

371

372

return writeJsonResponse(exchange, returnValue)

373

.doOnError(ex -> logger.error("Failed to write JSON response", ex));

374

}

375

376

private Mono<Void> writeJsonResponse(ServerWebExchange exchange, Object value) {

377

try {

378

String json = objectMapper.writeValueAsString(value);

379

ServerHttpResponse response = exchange.getResponse();

380

381

response.getHeaders().setContentType(MediaType.APPLICATION_JSON);

382

DataBuffer buffer = response.bufferFactory().wrap(json.getBytes());

383

384

return response.writeWith(Mono.just(buffer));

385

} catch (Exception e) {

386

return Mono.error(e);

387

}

388

}

389

}

390

391

// Built-in result handlers configuration

392

@Configuration

393

public class ResultHandlerConfig {

394

395

@Bean

396

public ResponseEntityResultHandler responseEntityResultHandler() {

397

return new ResponseEntityResultHandler(List.of(new JsonMessageWriter()),

398

contentTypeResolver());

399

}

400

401

@Bean

402

public ResponseBodyResultHandler responseBodyResultHandler() {

403

return new ResponseBodyResultHandler(List.of(new JsonMessageWriter()),

404

contentTypeResolver());

405

}

406

407

@Bean

408

public ViewResolutionResultHandler viewResolutionResultHandler() {

409

return new ViewResolutionResultHandler(viewResolvers(),

410

contentTypeResolver());

411

}

412

}

413

```

414

415

### Binding Context

416

417

Context for data binding operations and shared model management across request processing.

418

419

```java { .api }

420

class BindingContext {

421

/**

422

* Create a new BindingContext.

423

*/

424

BindingContext();

425

426

/**

427

* Create a new BindingContext with a WebBindingInitializer.

428

* @param initializer the initializer to use

429

*/

430

BindingContext(WebBindingInitializer initializer);

431

432

/**

433

* Create a new BindingContext with initializer and adapter registry.

434

* @param initializer the initializer to use

435

* @param registry the reactive adapter registry

436

*/

437

BindingContext(WebBindingInitializer initializer, ReactiveAdapterRegistry registry);

438

439

/**

440

* Return the default model for the request.

441

*/

442

Model getModel();

443

444

/**

445

* Create a WebExchangeDataBinder for the target object.

446

* @param exchange the current exchange

447

* @param target the target object to bind to

448

* @param name the name of the target object

449

* @return the data binder

450

*/

451

WebExchangeDataBinder createDataBinder(ServerWebExchange exchange, Object target, String name);

452

453

/**

454

* Create a WebExchangeDataBinder without a target object.

455

* @param exchange the current exchange

456

* @param name the name for the binder

457

* @return the data binder

458

*/

459

WebExchangeDataBinder createDataBinder(ServerWebExchange exchange, String name);

460

461

/**

462

* Configure whether method validation is applicable.

463

* @param methodValidationApplicable true if method validation should be applied

464

*/

465

void setMethodValidationApplicable(boolean methodValidationApplicable);

466

467

/**

468

* Update the model before view rendering.

469

* @param exchange the current exchange

470

*/

471

void updateModel(ServerWebExchange exchange);

472

}

473

```

474

475

**Usage Examples:**

476

477

```java

478

// Using BindingContext in custom argument resolver

479

@Component

480

public class CustomModelAttributeResolver implements HandlerMethodArgumentResolver {

481

482

@Override

483

public boolean supportsParameter(MethodParameter parameter) {

484

return parameter.hasParameterAnnotation(ModelAttribute.class);

485

}

486

487

@Override

488

public Mono<Object> resolveArgument(MethodParameter parameter,

489

BindingContext bindingContext,

490

ServerWebExchange exchange) {

491

492

String name = getAttributeName(parameter);

493

Class<?> type = parameter.getParameterType();

494

495

// Create target object

496

Object target = BeanUtils.instantiateClass(type);

497

498

// Create data binder

499

WebExchangeDataBinder binder = bindingContext.createDataBinder(exchange, target, name);

500

501

// Bind request data

502

return binder.bind(exchange)

503

.doOnSuccess(result -> {

504

// Add to model

505

bindingContext.getModel().addAttribute(name, target);

506

})

507

.then(Mono.just(target));

508

}

509

}

510

511

// Using BindingContext in controller method

512

@RestController

513

public class UserController {

514

515

@PostMapping("/users")

516

public Mono<User> createUser(@RequestBody User user,

517

BindingContext bindingContext,

518

ServerWebExchange exchange) {

519

520

// Create validator

521

WebExchangeDataBinder binder = bindingContext.createDataBinder(exchange, user, "user");

522

523

return binder.bind(exchange)

524

.then(Mono.fromCallable(() -> {

525

BindingResult result = binder.getBindingResult();

526

if (result.hasErrors()) {

527

throw new ValidationException(result);

528

}

529

return user;

530

}))

531

.flatMap(userService::save);

532

}

533

}

534

```

535

536

### Dispatch Exception Handler

537

538

Interface for mapping exceptions to handler results, providing centralized exception handling.

539

540

```java { .api }

541

@FunctionalInterface

542

interface DispatchExceptionHandler {

543

/**

544

* Handle the given exception and return a HandlerResult.

545

* @param exchange the current exchange

546

* @param ex the exception to handle

547

* @return the handler result for the exception

548

*/

549

Mono<HandlerResult> handleError(ServerWebExchange exchange, Throwable ex);

550

}

551

```

552

553

**Usage Examples:**

554

555

```java

556

// Custom exception handler

557

@Component

558

public class CustomExceptionHandler implements DispatchExceptionHandler {

559

560

@Override

561

public Mono<HandlerResult> handleError(ServerWebExchange exchange, Throwable ex) {

562

if (ex instanceof ValidationException) {

563

return handleValidationException(exchange, (ValidationException) ex);

564

} else if (ex instanceof SecurityException) {

565

return handleSecurityException(exchange, (SecurityException) ex);

566

}

567

568

return handleGenericException(exchange, ex);

569

}

570

571

private Mono<HandlerResult> handleValidationException(ServerWebExchange exchange, ValidationException ex) {

572

ErrorResponse error = new ErrorResponse("VALIDATION_ERROR", ex.getErrors());

573

HandlerResult result = new HandlerResult(this, error, null);

574

575

exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);

576

return Mono.just(result);

577

}

578

579

private Mono<HandlerResult> handleSecurityException(ServerWebExchange exchange, SecurityException ex) {

580

ErrorResponse error = new ErrorResponse("ACCESS_DENIED", ex.getMessage());

581

HandlerResult result = new HandlerResult(this, error, null);

582

583

exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);

584

return Mono.just(result);

585

}

586

}

587

588

// Configure exception handling in WebFlux

589

@Configuration

590

public class ExceptionHandlingConfig {

591

592

@Bean

593

public WebExceptionHandler customWebExceptionHandler() {

594

return new CustomWebExceptionHandler();

595

}

596

597

@Order(-2) // Higher priority than default handlers

598

public static class CustomWebExceptionHandler implements WebExceptionHandler {

599

600

private final DispatchExceptionHandler exceptionHandler;

601

602

public CustomWebExceptionHandler(DispatchExceptionHandler exceptionHandler) {

603

this.exceptionHandler = exceptionHandler;

604

}

605

606

@Override

607

public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {

608

return exceptionHandler.handleError(exchange, ex)

609

.flatMap(result -> writeErrorResponse(exchange, result))

610

.onErrorResume(error -> writeGenericError(exchange, error));

611

}

612

}

613

}

614

```