Browse Source

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
pull/24697/head
Arjen Poutsma 6 years ago
parent
commit
7c4f0318bb
  1. 36
      spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctionBuilder.java
  2. 2
      spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java
  3. 40
      spring-webmvc/src/main/java/org/springframework/web/servlet/function/RouterFunctionBuilder.java
  4. 4
      spring-webmvc/src/main/java/org/springframework/web/servlet/function/RouterFunctions.java

36
spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctionBuilder.java

@ -1,5 +1,5 @@ @@ -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; @@ -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 { @@ -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 { @@ -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));
}
}
}

2
spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java

@ -749,7 +749,7 @@ public abstract class RouterFunctions { @@ -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() {

40
spring-webmvc/src/main/java/org/springframework/web/servlet/function/RouterFunctionBuilder.java

@ -1,5 +1,5 @@ @@ -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 { @@ -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 { @@ -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));
}
}
}

4
spring-webmvc/src/main/java/org/springframework/web/servlet/function/RouterFunctions.java

@ -1,5 +1,5 @@ @@ -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 { @@ -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() {

Loading…
Cancel
Save