Improve efficiency of built RouterFunction
This commit changes the way RouterFunctions registered to the builder are composed in both WebFlux.fn and WebMvc.fn. Prior to this commit, all routes added to the build were composed with `reduce`. After this commit, all routes are stored in a special router function, allowing for more efficient execution and smaller stack traces. Closes gh-24652
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -241,9 +242,10 @@ class RouterFunctionBuilder implements RouterFunctions.Builder {
|
||||
|
||||
@Override
|
||||
public RouterFunction<ServerResponse> build() {
|
||||
RouterFunction<ServerResponse> result = this.routerFunctions.stream()
|
||||
.reduce(RouterFunction::and)
|
||||
.orElseThrow(IllegalStateException::new);
|
||||
if (this.routerFunctions.isEmpty()) {
|
||||
throw new IllegalStateException("No routes registered. Register a route with GET(), POST(), etc.");
|
||||
}
|
||||
RouterFunction<ServerResponse> result = new BuiltRouterFunction(this.routerFunctions);
|
||||
|
||||
if (this.filterFunctions.isEmpty()) {
|
||||
return result;
|
||||
@@ -258,4 +260,30 @@ class RouterFunctionBuilder implements RouterFunctions.Builder {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Router function returned by {@link #build()} that simply iterates over the registered routes.
|
||||
*/
|
||||
private static class BuiltRouterFunction extends RouterFunctions.AbstractRouterFunction<ServerResponse> {
|
||||
|
||||
private List<RouterFunction<ServerResponse>> routerFunctions;
|
||||
|
||||
public BuiltRouterFunction(List<RouterFunction<ServerResponse>> routerFunctions) {
|
||||
Assert.notEmpty(routerFunctions, "RouterFunctions must not be empty");
|
||||
this.routerFunctions = routerFunctions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<HandlerFunction<ServerResponse>> route(ServerRequest request) {
|
||||
return Flux.fromIterable(this.routerFunctions)
|
||||
.concatMap(routerFunction -> routerFunction.route(request))
|
||||
.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(RouterFunctions.Visitor visitor) {
|
||||
this.routerFunctions.forEach(routerFunction -> routerFunction.accept(visitor));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -749,7 +749,7 @@ public abstract class RouterFunctions {
|
||||
}
|
||||
|
||||
|
||||
private abstract static class AbstractRouterFunction<T extends ServerResponse> implements RouterFunction<T> {
|
||||
abstract static class AbstractRouterFunction<T extends ServerResponse> implements RouterFunction<T> {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -237,9 +237,10 @@ class RouterFunctionBuilder implements RouterFunctions.Builder {
|
||||
|
||||
@Override
|
||||
public RouterFunction<ServerResponse> build() {
|
||||
RouterFunction<ServerResponse> result = this.routerFunctions.stream()
|
||||
.reduce(RouterFunction::and)
|
||||
.orElseThrow(IllegalStateException::new);
|
||||
if (this.routerFunctions.isEmpty()) {
|
||||
throw new IllegalStateException("No routes registered. Register a route with GET(), POST(), etc.");
|
||||
}
|
||||
RouterFunction<ServerResponse> result = new BuiltRouterFunction(this.routerFunctions);
|
||||
|
||||
if (this.filterFunctions.isEmpty()) {
|
||||
return result;
|
||||
@@ -254,4 +255,35 @@ class RouterFunctionBuilder implements RouterFunctions.Builder {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Router function returned by {@link #build()} that simply iterates over the registered routes.
|
||||
*/
|
||||
private static class BuiltRouterFunction extends RouterFunctions.AbstractRouterFunction<ServerResponse> {
|
||||
|
||||
private List<RouterFunction<ServerResponse>> routerFunctions;
|
||||
|
||||
public BuiltRouterFunction(List<RouterFunction<ServerResponse>> routerFunctions) {
|
||||
Assert.notEmpty(routerFunctions, "RouterFunctions must not be empty");
|
||||
this.routerFunctions = routerFunctions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<HandlerFunction<ServerResponse>> route(ServerRequest request) {
|
||||
for (RouterFunction<ServerResponse> routerFunction : this.routerFunctions) {
|
||||
Optional<HandlerFunction<ServerResponse>> result = routerFunction.route(request);
|
||||
if (result.isPresent()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(RouterFunctions.Visitor visitor) {
|
||||
this.routerFunctions.forEach(routerFunction -> routerFunction.accept(visitor));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -660,7 +660,7 @@ public abstract class RouterFunctions {
|
||||
}
|
||||
|
||||
|
||||
private abstract static class AbstractRouterFunction<T extends ServerResponse> implements RouterFunction<T> {
|
||||
abstract static class AbstractRouterFunction<T extends ServerResponse> implements RouterFunction<T> {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
Reference in New Issue
Block a user