diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml
index 1e8d5217..45229626 100644
--- a/spring-cloud-gateway-sample/pom.xml
+++ b/spring-cloud-gateway-sample/pom.xml
@@ -34,6 +34,11 @@
org.springframework.cloud
spring-cloud-starter-gateway
+
+ org.isomorphism
+ token-bucket
+ 1.7
+
org.springframework.boot
spring-boot-starter-test
diff --git a/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/GatewaySampleApplication.java b/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/GatewaySampleApplication.java
index 9035199a..8232830f 100644
--- a/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/GatewaySampleApplication.java
+++ b/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/GatewaySampleApplication.java
@@ -28,6 +28,7 @@ import org.springframework.context.annotation.Bean;
import static org.springframework.cloud.gateway.filter.factory.WebFilterFactories.addResponseHeader;
import static org.springframework.cloud.gateway.handler.predicate.RoutePredicates.host;
import static org.springframework.cloud.gateway.handler.predicate.RoutePredicates.path;
+import static org.springframework.tuple.TupleBuilder.tuple;
/**
* @author Spencer Gibb
@@ -38,7 +39,7 @@ import static org.springframework.cloud.gateway.handler.predicate.RoutePredicate
public class GatewaySampleApplication {
@Bean
- public RouteLocator customRouteLocator() {
+ public RouteLocator customRouteLocator(ThrottleWebFilterFactory throttle) {
return Routes.locator()
.route("test")
.uri("http://httpbin.org:80")
@@ -50,9 +51,23 @@ public class GatewaySampleApplication {
.predicate(path("/image/webp"))
.add(addResponseHeader("X-AnotherHeader", "baz"))
.and()
+ .route("test3")
+ .order(-1)
+ .uri("http://httpbin.org:80")
+ .predicate(host("**.throttle.org").and(path("/get")))
+ .add(throttle.apply(tuple().of("capacity", 1,
+ "refillTokens", 1,
+ "refillPeriod", 10,
+ "refillUnit", "SECONDS")))
+ .and()
.build();
}
+ @Bean
+ public ThrottleWebFilterFactory throttleWebFilterFactory() {
+ return new ThrottleWebFilterFactory();
+ }
+
public static void main(String[] args) {
SpringApplication.run(GatewaySampleApplication.class, args);
}
diff --git a/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/ThrottleWebFilterFactory.java b/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/ThrottleWebFilterFactory.java
new file mode 100644
index 00000000..dba50411
--- /dev/null
+++ b/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/ThrottleWebFilterFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2013-2017 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
+ *
+ * http://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.sample;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.isomorphism.util.TokenBucket;
+import org.isomorphism.util.TokenBuckets;
+import org.springframework.cloud.gateway.filter.factory.WebFilterFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.tuple.Tuple;
+import org.springframework.web.server.WebFilter;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Sample throttling filter.
+ * See https://github.com/bbeck/token-bucket
+ */
+public class ThrottleWebFilterFactory implements WebFilterFactory {
+ private Log log = LogFactory.getLog(getClass());
+
+ @Override
+ public WebFilter apply(Tuple args) {
+ int capacity = args.getInt("capacity");
+ int refillTokens = args.getInt("refillTokens");
+ int refillPeriod = args.getInt("refillPeriod");
+ TimeUnit refillUnit = TimeUnit.valueOf(args.getString("refillUnit"));
+
+ final TokenBucket tokenBucket = TokenBuckets.builder()
+ .withCapacity(capacity)
+ .withFixedIntervalRefillStrategy(refillTokens, refillPeriod, refillUnit)
+ .build();
+
+ return (exchange, chain) -> {
+ log.debug("TokenBucket capacity: " + tokenBucket.getCapacity());
+ boolean consumed = tokenBucket.tryConsume();
+ if (consumed) {
+ return chain.filter(exchange);
+ }
+ exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
+ return exchange.getResponse().setComplete();
+ };
+ }
+}