From 1c759ec8d5717b935e0faf3d05ae61e8d7e23c0c Mon Sep 17 00:00:00 2001 From: tiger Date: Thu, 21 Feb 2019 15:18:34 +0800 Subject: [PATCH 1/5] add spring-cloud-alibaba-sentinel-zuul module --- pom.xml | 2 + spring-cloud-alibaba-sentinel-zuul/README.md | 141 ++++++++++++++++++ spring-cloud-alibaba-sentinel-zuul/pom.xml | 43 ++++++ .../zuul/SentinelZuulAutoConfiguration.java | 116 ++++++++++++++ .../listener/FallBackProviderListener.java | 38 +++++ .../main/resources/META-INF/spring.factories | 2 + 6 files changed, 342 insertions(+) create mode 100755 spring-cloud-alibaba-sentinel-zuul/README.md create mode 100644 spring-cloud-alibaba-sentinel-zuul/pom.xml create mode 100644 spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java create mode 100644 spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/listener/FallBackProviderListener.java create mode 100644 spring-cloud-alibaba-sentinel-zuul/src/main/resources/META-INF/spring.factories diff --git a/pom.xml b/pom.xml index 94a52385..ac6ae996 100644 --- a/pom.xml +++ b/pom.xml @@ -59,6 +59,7 @@ 2.0.0.RELEASE 2.0.0.RELEASE + 4.12 3.0 1.7.25 @@ -82,6 +83,7 @@ spring-cloud-starter-alibaba spring-cloud-starter-alicloud spring-cloud-alicloud-oss + spring-cloud-alibaba-sentinel-zuul diff --git a/spring-cloud-alibaba-sentinel-zuul/README.md b/spring-cloud-alibaba-sentinel-zuul/README.md new file mode 100755 index 00000000..2d0d2fd1 --- /dev/null +++ b/spring-cloud-alibaba-sentinel-zuul/README.md @@ -0,0 +1,141 @@ +# Sentinel Spring Cloud Zuul Adapter + +Zuul does not provide rateLimit function, If use default `SentinelRibbonFilter` route filter. it wrapped by Hystrix Command. so only provide Service level +circuit protect. + +Sentinel can provide `ServiceId` level and `API Path` level flow control for spring cloud zuul gateway service. + +*Note*: this project is for zuul 1. + +## How to use + +1. Add maven dependency + +```xml + + org.springframework.cloud + spring-cloud-alibaba-sentinel-zuul + x.y.z + + +``` + +2. Set application.property + +``` +// default value is false +spring.cloud.sentinel.zuul.enabled=true +``` + +## How it works + +As Zuul run as per thread per connection block model, we add filters around `route Filter` to trace sentinel statistics. + +- `SentinelPreFilter`: Get an entry of resource,the first order is **ServiceId**, then **API Path**. +- `SentinelPostFilter`: When success response,exit entry. +- `SentinelErrorFilter`: When get an `Exception`, trace the exception and exit context. + + +the order of Filter can be changed by configuration: + +``` +spring.cloud.sentinel.zuul.order.post=0 +spring.cloud.sentinel.zuul.order.pre=10000 +spring.cloud.sentinel.zuul.order.error=-1 +``` + + +Filters create structure like: + + +```bash + +EntranceNode: machine-root(t:3 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0) +-EntranceNode: coke(t:2 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0) +--coke(t:2 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0) +---/coke/uri(t:0 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0) +-EntranceNode: sentinel_default_context(t:0 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0) +-EntranceNode: book(t:1 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0) +--book(t:1 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0) +---/book/uri(t:0 pq:0 bq:0 tq:0 rt:0 prq:0 1mp:0 1mb:0 1mt:0) + +``` + +`book` and `coke` are serviceId. + +`---/book/uri` is api path, the real uri is `/uri`. + + +## Integration with Sentinel DashBord + +Start [Sentinel DashBord](https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0). + +## Rule config with dataSource + +Sentinel has full rule config features. see [Dynamic-Rule-Configuration](https://github.com/alibaba/Sentinel/wiki/Dynamic-Rule-Configuration) + + +## Custom Fallbacks + +Implements `SentinelFallbackProvider` to define your own Fallback Provider when Sentinel Block Exception throwing for different rout. the default +Fallback Provider is `DefaultBlockFallbackProvider`. + +By default Fallback route is `ServiveId + URI PATH`, example `/book/coke`, first `book` is serviceId, `/uri` is URI PATH, so both +can be needed. + +Here is an example: + +```java + +// custom provider +public class MyCokeServiceBlockFallbackProvider implements SentinelFallbackProvider { + + private Logger logger = LoggerFactory.getLogger(DefaultBlockFallbackProvider.class); + + // you can define root as service level + @Override + public String getRoute() { + return "/coke/uri"; + } + + @Override + public ClientHttpResponse fallbackResponse(String route, Throwable cause) { + if (cause instanceof BlockException) { + logger.info("get in fallback block exception:{}", cause); + return response(HttpStatus.TOO_MANY_REQUESTS, route); + } else { + return response(HttpStatus.INTERNAL_SERVER_ERROR, route); + } + } + } + +``` + +## Custom Request Origin Parser +By default this adapter use `DefaultRequestOriginParser` to parse sentinel origin. + +```java + +public class CustomRequestOriginParser implements RequestOriginParser { + @Override + public String parseOrigin(HttpServletRequest request) { + // do custom logic. + return ""; + } +} + +``` + +## Custom UrlCleaner +By default this adapter use `DefaultUrlCleaner` to define uri resource. + +```java +public class CustomUrlCleaner implements UrlCleaner { + + @Override + public String clean(String originUrl) { + // do custom logic. + return originUrl; + } +} +``` \ No newline at end of file diff --git a/spring-cloud-alibaba-sentinel-zuul/pom.xml b/spring-cloud-alibaba-sentinel-zuul/pom.xml new file mode 100644 index 00000000..60ae2dff --- /dev/null +++ b/spring-cloud-alibaba-sentinel-zuul/pom.xml @@ -0,0 +1,43 @@ + + + + spring-cloud-alibaba + org.springframework.cloud + 0.2.0.BUILD-SNAPSHOT + + 4.0.0 + + spring-cloud-alibaba-sentinel-zuul + + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + provided + + + com.alibaba.csp + sentinel-zuul-adapter + 1.4.2 + + + org.springframework.boot + spring-boot-configuration-processor + provided + true + + + junit + junit + test + + + org.mockito + mockito-core + test + + + + \ No newline at end of file diff --git a/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java b/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java new file mode 100644 index 00000000..9fc77637 --- /dev/null +++ b/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java @@ -0,0 +1,116 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * 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.alibaba.sentinel.zuul; + +import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultRequestOriginParser; +import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultUrlCleaner; +import com.alibaba.csp.sentinel.adapter.zuul.fallback.RequestOriginParser; +import com.alibaba.csp.sentinel.adapter.zuul.fallback.UrlCleaner; +import com.alibaba.csp.sentinel.adapter.zuul.filters.SentinelErrorFilter; +import com.alibaba.csp.sentinel.adapter.zuul.filters.SentinelPostFilter; +import com.alibaba.csp.sentinel.adapter.zuul.filters.SentinelPreFilter; +import com.alibaba.csp.sentinel.adapter.zuul.properties.SentinelZuulProperties; +import com.alibaba.csp.sentinel.util.StringUtil; +import com.netflix.zuul.ZuulFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.alibaba.sentinel.zuul.listener.FallBackProviderListener; +import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +import static org.springframework.cloud.alibaba.sentinel.zuul.SentinelZuulAutoConfiguration.PREFIX; + +/** + * Sentinel Spring Cloud Zuul AutoConfiguration + * + * @author tiger + */ +@Configuration +@ConditionalOnProperty(prefix = PREFIX, name = "enabled", havingValue = "true") +public class SentinelZuulAutoConfiguration { + + @Autowired + private Environment environment; + + public static final String PREFIX = "spring.cloud.alibaba.sentinel.zuul"; + + @Bean + public SentinelZuulProperties sentinelZuulProperties() { + SentinelZuulProperties properties = new SentinelZuulProperties(); + String enabledStr = environment.getProperty(PREFIX + "." + "enabled"); + String preOrderStr = environment.getProperty(PREFIX + "." + "order.pre"); + String postOrderStr = environment.getProperty(PREFIX + "." + "order.post"); + String errorOrderStr = environment.getProperty(PREFIX + "." + "order.error"); + if (StringUtil.isNotEmpty(enabledStr)) { + Boolean enabled = Boolean.valueOf(enabledStr); + properties.setEnabled(enabled); + } + if (StringUtil.isNotEmpty(preOrderStr)) { + properties.getOrder().setPre(Integer.parseInt(preOrderStr)); + } + if (StringUtil.isNotEmpty(postOrderStr)) { + properties.getOrder().setPost(Integer.parseInt(postOrderStr)); + } + if (StringUtil.isNotEmpty(errorOrderStr)) { + properties.getOrder().setError(Integer.parseInt(errorOrderStr)); + } + return properties; + } + + @Bean + @ConditionalOnMissingBean(ProxyRequestHelper.class) + public ProxyRequestHelper proxyRequestHelper() { + return new ProxyRequestHelper(); + } + + @Bean + @ConditionalOnMissingBean(UrlCleaner.class) + public UrlCleaner urlCleaner(){ + return new DefaultUrlCleaner(); + } + + @Bean + @ConditionalOnMissingBean(RequestOriginParser.class) + public RequestOriginParser requestOriginParser(){ + return new DefaultRequestOriginParser(); + } + + @Bean + public ZuulFilter preFilter(SentinelZuulProperties sentinelZuulProperties,UrlCleaner urlCleaner, + RequestOriginParser requestOriginParser) { + return new SentinelPreFilter(sentinelZuulProperties,urlCleaner,requestOriginParser); + } + + @Bean + public ZuulFilter postFilter(SentinelZuulProperties sentinelZuulProperties) { + return new SentinelPostFilter(sentinelZuulProperties); + } + + @Bean + public ZuulFilter errorFilter(SentinelZuulProperties sentinelZuulProperties) { + return new SentinelErrorFilter(sentinelZuulProperties); + } + + @Bean + public FallBackProviderListener fallBackProviderListener() { + return new FallBackProviderListener(); + } + +} diff --git a/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/listener/FallBackProviderListener.java b/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/listener/FallBackProviderListener.java new file mode 100644 index 00000000..d4d19bdf --- /dev/null +++ b/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/listener/FallBackProviderListener.java @@ -0,0 +1,38 @@ +package org.springframework.cloud.alibaba.sentinel.zuul.listener; + +import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultBlockFallbackProvider; +import com.alibaba.csp.sentinel.adapter.zuul.fallback.ZuulBlockFallbackManager; +import com.alibaba.csp.sentinel.adapter.zuul.fallback.ZuulBlockFallbackProvider; +import org.apache.commons.collections.MapUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.context.event.ApplicationStartedEvent; +import org.springframework.context.event.EventListener; + +import java.util.Map; + + +/** + * @author tiger + */ +public class FallBackProviderListener { + + private static final Logger logger = LoggerFactory.getLogger(FallBackProviderListener.class); + + @EventListener(classes = ApplicationStartedEvent.class) + public void appStartedListener(ApplicationStartedEvent event) throws Exception { + Map providerMap = event.getApplicationContext().getBeansOfType( + ZuulBlockFallbackProvider.class); + if (MapUtils.isNotEmpty(providerMap)) { + providerMap.forEach((k, v) -> { + logger.info("[Sentinel] Register provider name: {}, instance: {}", k, v); + ZuulBlockFallbackManager.registerProvider(v); + }); + } else { + logger.info("[Sentinel] Register default fallback provider. "); + ZuulBlockFallbackManager.registerProvider(new DefaultBlockFallbackProvider()); + } + } + + +} diff --git a/spring-cloud-alibaba-sentinel-zuul/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-sentinel-zuul/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..b4ced151 --- /dev/null +++ b/spring-cloud-alibaba-sentinel-zuul/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.springframework.cloud.alibaba.sentinel.zuul.SentinelZuulAutoConfiguration \ No newline at end of file From 356f07a5092359a9c59f330a9823ac94a33b806c Mon Sep 17 00:00:00 2001 From: tiger Date: Thu, 21 Feb 2019 15:34:21 +0800 Subject: [PATCH 2/5] remove version and format code --- pom.xml | 2 +- spring-cloud-alibaba-sentinel-zuul/pom.xml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1079f292..5ad92ead 100644 --- a/pom.xml +++ b/pom.xml @@ -88,6 +88,7 @@ spring-cloud-alibaba-dependencies spring-cloud-alibaba-sentinel spring-cloud-alibaba-sentinel-datasource + spring-cloud-alibaba-sentinel-zuul spring-cloud-alibaba-nacos-config spring-cloud-alibaba-nacos-discovery spring-cloud-alibaba-fescar @@ -105,7 +106,6 @@ spring-cloud-alicloud-ans spring-cloud-alicloud-schedulerx spring-cloud-alicloud-sms - spring-cloud-alibaba-sentinel-zuul diff --git a/spring-cloud-alibaba-sentinel-zuul/pom.xml b/spring-cloud-alibaba-sentinel-zuul/pom.xml index 60ae2dff..50065b45 100644 --- a/spring-cloud-alibaba-sentinel-zuul/pom.xml +++ b/spring-cloud-alibaba-sentinel-zuul/pom.xml @@ -20,7 +20,6 @@ com.alibaba.csp sentinel-zuul-adapter - 1.4.2 org.springframework.boot From 19af00793161f88ae8cdff2085181ca19f73ea9b Mon Sep 17 00:00:00 2001 From: tiger Date: Thu, 21 Feb 2019 15:51:01 +0800 Subject: [PATCH 3/5] update spring cloud version --- spring-cloud-alibaba-sentinel-zuul/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-alibaba-sentinel-zuul/pom.xml b/spring-cloud-alibaba-sentinel-zuul/pom.xml index 50065b45..3524212a 100644 --- a/spring-cloud-alibaba-sentinel-zuul/pom.xml +++ b/spring-cloud-alibaba-sentinel-zuul/pom.xml @@ -5,7 +5,7 @@ spring-cloud-alibaba org.springframework.cloud - 0.2.0.BUILD-SNAPSHOT + 0.2.2.BUILD-SNAPSHOT 4.0.0 From ac25e4a9dc266d3da05282d003c76de51dc8c38d Mon Sep 17 00:00:00 2001 From: tiger Date: Thu, 21 Feb 2019 16:32:01 +0800 Subject: [PATCH 4/5] add sentinel-zuul-adapter dependency --- spring-cloud-alibaba-dependencies/pom.xml | 10 ++++++++++ spring-cloud-alibaba-sentinel-zuul/pom.xml | 2 ++ 2 files changed, 12 insertions(+) diff --git a/spring-cloud-alibaba-dependencies/pom.xml b/spring-cloud-alibaba-dependencies/pom.xml index 73f35e85..efd1ea82 100644 --- a/spring-cloud-alibaba-dependencies/pom.xml +++ b/spring-cloud-alibaba-dependencies/pom.xml @@ -148,6 +148,11 @@ sentinel-web-servlet ${sentinel.version} + + com.alibaba.csp + sentinel-zuul-adapter + ${sentinel.version} + com.alibaba.csp sentinel-transport-simple-http @@ -265,6 +270,11 @@ spring-cloud-alibaba-sentinel-datasource ${project.version} + + org.springframework.cloud + spring-cloud-alibaba-sentinel-zuul + ${project.version} + org.springframework.cloud spring-cloud-alicloud-oss diff --git a/spring-cloud-alibaba-sentinel-zuul/pom.xml b/spring-cloud-alibaba-sentinel-zuul/pom.xml index 3524212a..d8f8fa80 100644 --- a/spring-cloud-alibaba-sentinel-zuul/pom.xml +++ b/spring-cloud-alibaba-sentinel-zuul/pom.xml @@ -9,7 +9,9 @@ 4.0.0 + org.springframework.cloud spring-cloud-alibaba-sentinel-zuul + Spring Cloud Alibaba Sentinel Zuul From ffb71e3eaf37cfa41b45d348bccdd20b19db55ee Mon Sep 17 00:00:00 2001 From: tiger Date: Fri, 22 Feb 2019 18:09:35 +0800 Subject: [PATCH 5/5] change listener to use SmartInitializingSingleton --- .../zuul/SentinelZuulAutoConfiguration.java | 12 +++-------- .../listener/FallBackProviderListener.java | 21 ++++++++++++------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java b/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java index 9fc77637..73d4cf79 100644 --- a/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java +++ b/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/SentinelZuulAutoConfiguration.java @@ -27,10 +27,10 @@ import com.alibaba.csp.sentinel.adapter.zuul.properties.SentinelZuulProperties; import com.alibaba.csp.sentinel.util.StringUtil; import com.netflix.zuul.ZuulFilter; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.alibaba.sentinel.zuul.listener.FallBackProviderListener; -import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; @@ -74,12 +74,6 @@ public class SentinelZuulAutoConfiguration { return properties; } - @Bean - @ConditionalOnMissingBean(ProxyRequestHelper.class) - public ProxyRequestHelper proxyRequestHelper() { - return new ProxyRequestHelper(); - } - @Bean @ConditionalOnMissingBean(UrlCleaner.class) public UrlCleaner urlCleaner(){ @@ -109,8 +103,8 @@ public class SentinelZuulAutoConfiguration { } @Bean - public FallBackProviderListener fallBackProviderListener() { - return new FallBackProviderListener(); + public FallBackProviderListener fallBackProviderListener(DefaultListableBeanFactory beanFactory) { + return new FallBackProviderListener(beanFactory); } } diff --git a/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/listener/FallBackProviderListener.java b/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/listener/FallBackProviderListener.java index d4d19bdf..d727a0e4 100644 --- a/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/listener/FallBackProviderListener.java +++ b/spring-cloud-alibaba-sentinel-zuul/src/main/java/org/springframework/cloud/alibaba/sentinel/zuul/listener/FallBackProviderListener.java @@ -6,6 +6,8 @@ import com.alibaba.csp.sentinel.adapter.zuul.fallback.ZuulBlockFallbackProvider; import org.apache.commons.collections.MapUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.context.event.EventListener; @@ -15,17 +17,22 @@ import java.util.Map; /** * @author tiger */ -public class FallBackProviderListener { +public class FallBackProviderListener implements SmartInitializingSingleton { private static final Logger logger = LoggerFactory.getLogger(FallBackProviderListener.class); - @EventListener(classes = ApplicationStartedEvent.class) - public void appStartedListener(ApplicationStartedEvent event) throws Exception { - Map providerMap = event.getApplicationContext().getBeansOfType( - ZuulBlockFallbackProvider.class); + private final DefaultListableBeanFactory beanFactory; + + public FallBackProviderListener(DefaultListableBeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + @Override + public void afterSingletonsInstantiated() { + Map providerMap = beanFactory.getBeansOfType(ZuulBlockFallbackProvider.class); if (MapUtils.isNotEmpty(providerMap)) { providerMap.forEach((k, v) -> { - logger.info("[Sentinel] Register provider name: {}, instance: {}", k, v); + logger.info("[Sentinel] Register provider name:{}, instance: {}", k, v); ZuulBlockFallbackManager.registerProvider(v); }); } else { @@ -33,6 +40,4 @@ public class FallBackProviderListener { ZuulBlockFallbackManager.registerProvider(new DefaultBlockFallbackProvider()); } } - - }