Browse Source

Merge remote-tracking branch 'origin/main' into add-hints-for-configurable-supertypes-and-generics

add-hints-for-configurable-supertypes-and-generics
Olga Maciaszek-Sharma 2 years ago
parent
commit
618da71548
  1. 8
      docs/src/main/asciidoc/spring-cloud-gateway.adoc
  2. 1
      pom.xml
  3. 1
      spring-cloud-gateway-sample/pom.xml
  4. 13
      spring-cloud-gateway-server/pom.xml
  5. 7
      spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/CachedBodyOutputMessage.java
  6. 5
      spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java
  7. 5
      spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java
  8. 82
      spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicatePathContainerAttrBenchMarkTests.java

8
docs/src/main/asciidoc/spring-cloud-gateway.adoc

@ -13,7 +13,7 @@ See the https://projects.spring.io/spring-cloud/[Spring Cloud Project page] for @@ -13,7 +13,7 @@ See the https://projects.spring.io/spring-cloud/[Spring Cloud Project page] for
If you include the starter, but you do not want the gateway to be enabled, set `spring.cloud.gateway.enabled=false`.
IMPORTANT: Spring Cloud Gateway is built on https://spring.io/projects/spring-boot#learn[Spring Boot 2.x], https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html[Spring WebFlux], and https://projectreactor.io/docs[Project Reactor].
IMPORTANT: Spring Cloud Gateway is built on https://spring.io/projects/spring-boot#learn[Spring Boot], https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html[Spring WebFlux], and https://projectreactor.io/docs[Project Reactor].
As a consequence, many of the familiar synchronous libraries (Spring Data and Spring Security, for example) and patterns you know may not apply when you use Spring Cloud Gateway.
If you are unfamiliar with these projects, we suggest you begin by reading their documentation to familiarize yourself with some new concepts before working with Spring Cloud Gateway.
@ -2564,7 +2564,7 @@ A per-route `response-timeout` with a negative value will disable the global `re @@ -2564,7 +2564,7 @@ A per-route `response-timeout` with a negative value will disable the global `re
response-timeout: -1
----
=== Fluent Java Routes API
== Fluent Java Routes API
To allow for simple configuration in Java, the `RouteLocatorBuilder` bean includes a fluent API.
The following listing shows how it works:
@ -2606,13 +2606,13 @@ This style also allows for more custom predicate assertions. @@ -2606,13 +2606,13 @@ This style also allows for more custom predicate assertions.
The predicates defined by `RouteDefinitionLocator` beans are combined using logical `and`.
By using the fluent Java API, you can use the `and()`, `or()`, and `negate()` operators on the `Predicate` class.
=== The `DiscoveryClient` Route Definition Locator
== The `DiscoveryClient` Route Definition Locator
You can configure the gateway to create routes based on services registered with a `DiscoveryClient` compatible service registry.
To enable this, set `spring.cloud.gateway.discovery.locator.enabled=true` and make sure a `DiscoveryClient` implementation (such as Netflix Eureka, Consul, or Zookeeper) is on the classpath and enabled.
==== Configuring Predicates and Filters For `DiscoveryClient` Routes
=== Configuring Predicates and Filters For `DiscoveryClient` Routes
By default, the gateway defines a single predicate and filter for routes created with a `DiscoveryClient`.

1
pom.xml

@ -57,7 +57,6 @@ @@ -57,7 +57,6 @@
<spring-cloud-circuitbreaker.version>3.0.1-SNAPSHOT</spring-cloud-circuitbreaker.version>
<spring-cloud-commons.version>4.0.2-SNAPSHOT</spring-cloud-commons.version>
<testcontainers.version>1.17.3</testcontainers.version>
<kotlin-maven-plugin.version>1.6.21</kotlin-maven-plugin.version>
</properties>
<dependencyManagement>

1
spring-cloud-gateway-sample/pom.xml

@ -95,7 +95,6 @@ @@ -95,7 +95,6 @@
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin-maven-plugin.version}</version>
<configuration>
<args>
<arg>-Xjsr305=strict</arg>

13
spring-cloud-gateway-server/pom.xml

@ -223,6 +223,18 @@ @@ -223,6 +223,18 @@
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.20</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.20</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core-test</artifactId>
@ -235,7 +247,6 @@ @@ -235,7 +247,6 @@
<!-- Based on instructions here - https://kotlinlang.org/docs/reference/using-maven.html -->
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin-maven-plugin.version}</version>
<configuration>
<jvmTarget>17</jvmTarget>
</configuration>

7
spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/CachedBodyOutputMessage.java

@ -40,8 +40,7 @@ public class CachedBodyOutputMessage implements ReactiveHttpOutputMessage { @@ -40,8 +40,7 @@ public class CachedBodyOutputMessage implements ReactiveHttpOutputMessage {
private boolean cached = false;
private Flux<DataBuffer> body = Flux
.error(new IllegalStateException("The body is not set. " + "Did handling complete with success?"));
private Flux<DataBuffer> body = null;
public CachedBodyOutputMessage(ServerWebExchange exchange, HttpHeaders httpHeaders) {
this.bufferFactory = exchange.getResponse().bufferFactory();
@ -77,6 +76,10 @@ public class CachedBodyOutputMessage implements ReactiveHttpOutputMessage { @@ -77,6 +76,10 @@ public class CachedBodyOutputMessage implements ReactiveHttpOutputMessage {
* @return body as {@link Flux}
*/
public Flux<DataBuffer> getBody() {
if (body == null) {
return Flux
.error(new IllegalStateException("The body is not set. " + "Did handling complete with success?"));
}
return this.body;
}

5
spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java

@ -34,6 +34,7 @@ import org.springframework.web.util.pattern.PathPatternParser; @@ -34,6 +34,7 @@ import org.springframework.web.util.pattern.PathPatternParser;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_PREDICATE_MATCHED_PATH_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_PREDICATE_MATCHED_PATH_ROUTE_ID_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_PREDICATE_PATH_CONTAINER_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.putUriTemplateVariables;
import static org.springframework.http.server.PathContainer.parsePath;
@ -89,7 +90,9 @@ public class PathRoutePredicateFactory extends AbstractRoutePredicateFactory<Pat @@ -89,7 +90,9 @@ public class PathRoutePredicateFactory extends AbstractRoutePredicateFactory<Pat
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange exchange) {
PathContainer path = parsePath(exchange.getRequest().getURI().getRawPath());
PathContainer path = (PathContainer) exchange.getAttributes().computeIfAbsent(
GATEWAY_PREDICATE_PATH_CONTAINER_ATTR,
s -> parsePath(exchange.getRequest().getURI().getRawPath()));
PathPattern match = null;
for (int i = 0; i < pathPatterns.size(); i++) {

5
spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ServerWebExchangeUtils.java

@ -127,6 +127,11 @@ public final class ServerWebExchangeUtils { @@ -127,6 +127,11 @@ public final class ServerWebExchangeUtils {
public static final String GATEWAY_PREDICATE_MATCHED_PATH_ROUTE_ID_ATTR = qualify(
"gatewayPredicateMatchedPathRouteIdAttr");
/**
* Gateway predicate path container attribute name.
*/
public static final String GATEWAY_PREDICATE_PATH_CONTAINER_ATTR = qualify("gatewayPredicatePathContainer");
/**
* Weight attribute name.
*/

82
spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicatePathContainerAttrBenchMarkTests.java

@ -0,0 +1,82 @@ @@ -0,0 +1,82 @@
/*
* Copyright 2013-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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.gateway.handler.predicate;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.function.Predicate;
import org.apache.commons.lang3.RandomStringUtils;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
import org.springframework.web.server.ServerWebExchange;
public class PathRoutePredicatePathContainerAttrBenchMarkTests {
private static List<Predicate<ServerWebExchange>> predicates;
private static String PATH_PATTERN_PREFIX;
private final static String HOST = "http://localhost:8080";
private final static int ROUTES_NUM = 2000;
static {
predicates = new LinkedList<>();
PATH_PATTERN_PREFIX = String.format("/%s/%s/", RandomStringUtils.random(20, true, false),
RandomStringUtils.random(10, true, false));
for (int i = 0; i < ROUTES_NUM; i++) {
PathRoutePredicateFactory.Config config = new PathRoutePredicateFactory.Config()
.setPatterns(Collections.singletonList(PATH_PATTERN_PREFIX + i)).setMatchTrailingSlash(true);
Predicate<ServerWebExchange> predicate = new PathRoutePredicateFactory().apply(config);
predicates.add(predicate);
}
}
@Benchmark
@Threads(2)
@Fork(2)
@BenchmarkMode(Mode.All)
@Warmup(iterations = 1, time = 3)
@Measurement(iterations = 10, time = 1)
public void testPathContainerAttr() {
Random random = new Random();
MockServerHttpRequest request = MockServerHttpRequest
.get(HOST + PATH_PATTERN_PREFIX + random.nextInt(ROUTES_NUM)).build();
MockServerWebExchange exchange = MockServerWebExchange.from(request);
for (Predicate<ServerWebExchange> predicate : predicates) {
if (predicate.test(exchange)) {
break;
}
}
}
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(args);
}
}
Loading…
Cancel
Save