作者:ligang 原文:http://www.spring4all.com/article/158
如何在Zuul中使用fallback功能
我们在项目中使用Spring cloud zuul的时候,有一种这样的需求,就是当我们的zuul进行路由分发时,如果后端服务没有启动,或者调用超时,这时候我们希望Zuul提供一种降级功能,而不是将异常暴露出来。
在Dalston版本中,Spring cloud zuul提供这种降级功能,操作步骤如下:
-
在主函数上添加
@EnbaleZuulProxy注解。 -
实现
ZuulFallbackProvider接口。
对应
ZuulFallbackProvider源码如下:
public interface ZuulFallbackProvider {/*** The route this fallback will be used for.* @return The route the fallback will be used for.*/public String getRoute();/*** Provides a fallback response.* @return The fallback response.*/public ClientHttpResponse fallbackResponse();}
我们只要实现该接口,并实现
publicClientHttpResponsefallbackResponse();方法,也就是说该方法会让我定义一个
ClientHttpResponse作为当异常出现时的返回内容。
通过源码我们可知,Zuul提供三个配置文件,每一个配置文件代表用不同种方式进行请求的转发:
-
RestClientRibbonConfiguration -
OkHttpRibbonConfiguration -
HttpClientRibbonConfiguration(默认情况)HttpClientRibbonConfiguration源码如下(只体现涉及fallback模块):
@Configuration@ConditionalOnRibbonHttpClientprotected static class HttpClientRibbonConfiguration {@Autowired(required = false)private Set<ZuulFallbackProvider> zuulFallbackProviders = Collections.emptySet();@Bean@ConditionalOnMissingBeanpublic RibbonCommandFactory<?> ribbonCommandFactory(SpringClientFactory clientFactory, ZuulProperties zuulProperties){return new HttpClientRibbonCommandFactory(clientFactory,zuulProperties,zuulFallbackProviders);}}
通过源码我们可以了解,Zuul将你自定义的fallbackprovider保存在一个Set集合中,并作为
HttpClientRibbonCommandFactory构造器的参数。
当zuul在转发请求时最终会利用
AbstractRibbonCommand进行处理。通过源码我们知道
AbstractRibbonCommand继承了
HystrixCommand,所以真正转发请求的业务逻辑是在重写
HystrixCommand类的
run方法中进行的。
具体源码如下:
@Overrideprotected ClientHttpResponse run() throws Exception {final RequestContext context = RequestContext.getCurrentContext();RQ request = createRequest();RS response = this.client.executeWithLoadBalancer(request, config);context.set("ribbonResponse", response);// Explicitly close the HttpResponse if the Hystrix command timed out to// release the underlying HTTP connection held by the response.//if (this.isResponseTimedOut()) {if (response != null) {response.close();}}return new RibbonHttpResponse(response);}
我们知道
HystrixCommand提供
getFallback()方法,这个方法的作用是当
run()方法执行出现异常时,会自动调用
getFallback()方法,从而完成降级功能。(
HystrixCommand是Hystrix的知识,有兴趣的同学可以参照官方git文档)。
由于
AbstractRibbonCommand继承了
HystrixCommand,它不仅重写了
run()方法,而且重写了
getFallback()方法,具体源码如下:
@Overrideprotected ClientHttpResponse getFallback() {if(zuulFallbackProvider != null) {return zuulFallbackProvider.fallbackResponse();}return super.getFallback();}
通过源码我们知道,首先会去判断是否存在自定义的zuulFallbackProvider,如果有,那么直接回调你自定义实现类的
fallbackResponse()方法。如果不存在会走
hystrix的
fallback逻辑(有可能直接抛出异常)。说到这里Zuul的降级原理大致就说完了,细心的朋友可以发现这样的一个问题,就是虽然Zuul提供了降级的回调方法
fallbackResponse(),但是这个方法是无参的,也就是说此时虽然你能够给调用端返回一个消息,但是此时你并不知道发生了什么样的异常(也就是说在这里你是获取不到异常信息的)。
Edgware.RC1版本的改进
在Edgware.RC1版本中Spring cloud zuul针对于降级进行了升级,升级的内容主要是解决上面说到的当降级出现时,怎样在降级方法中获取具体的异常信息。增加了一个接口
FallbackProvider,这个接口继承了现有的
ZuulFallbackProvider接口,源码如下:
public interface FallbackProvider extends ZuulFallbackProvider {/*** Provides a fallback response based on the cause of the failed execution.** @param cause cause of the main method failure* @return the fallback response*/ClientHttpResponse fallbackResponse(Throwable cause);
可以看到这个接口有一个方法,这个方法的参数是
Throwable,也就是说此时是用能力获取异常信息的。接下来改造的内容在
AbstractRibbonCommand类中,主要是对原有的
getFallback()进行改造,同时增加了一个
getFallbackResponse()方法。下面通过源码具体了解下:
@Overrideprotected ClientHttpResponse getFallback() {if(zuulFallbackProvider != null) {return getFallbackResponse();}return super.getFallback();}
可以看到从原来调用
zuulFallbackProvider.fallbackResponse();转而调用内部方法
getFallbackResponse()。
getFallbackResponse()源码如下:
protected ClientHttpResponse getFallbackResponse() {if (zuulFallbackProvider instanceof FallbackProvider) {Throwable cause = getFailedExecutionException();cause = cause == null ? getExecutionException() : cause;if (cause == null) {zuulFallbackProvider.fallbackResponse();} else {return ((FallbackProvider) zuulFallbackProvider).fallbackResponse(cause);}}return zuulFallbackProvider.fallbackResponse();}
通过源码可知,此时会根据
Throwable是否存在来决定走哪种类型的降级方法(原来的还是带有参数的)。
到此Zuul的实现降级的原理以及Edgware.RC1中的改进就介绍完了。
与本文作者深入交流扫如下二维码
也可点击原文阅读在spring4all.com交流
推荐阅读
优秀人才不缺工作机会,只缺适合自己的好机会。但是他们往往没有精力从海量机会中找到最适合的那个。100offer 会对平台上的人才和企业进行严格筛选,让「最好的人才」和「最好的公司」相遇。扫描下方二维码,注册 100offer,谈谈你对下一份工作的期待。一周内,收到 5-10 个满足你要求的好机会!