前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Edgware.RC1中ZuulFallbackProvider的改进

Edgware.RC1中ZuulFallbackProvider的改进

作者头像
程序猿DD
发布2018-02-01 19:05:44
8930
发布2018-02-01 19:05:44
举报
文章被收录于专栏:程序猿DD

作者:ligang 原文:http://www.spring4all.com/article/158

如何在Zuul中使用fallback功能

我们在项目中使用Spring cloud zuul的时候,有一种这样的需求,就是当我们的zuul进行路由分发时,如果后端服务没有启动,或者调用超时,这时候我们希望Zuul提供一种降级功能,而不是将异常暴露出来。

在Dalston版本中,Spring cloud zuul提供这种降级功能,操作步骤如下:

  • 在主函数上添加 @EnbaleZuulProxy注解。
  • 实现 ZuulFallbackProvider接口。

对应 ZuulFallbackProvider源码如下:

代码语言:javascript
复制
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模块):
代码语言:javascript
复制
@Configuration
@ConditionalOnRibbonHttpClient
protected static class HttpClientRibbonConfiguration {

    @Autowired(required = false)
    private Set<ZuulFallbackProvider> zuulFallbackProviders = Collections.emptySet();
    @Bean
    @ConditionalOnMissingBean
    public RibbonCommandFactory<?> ribbonCommandFactory(
        SpringClientFactory clientFactory, ZuulProperties zuulProperties
    ) 
    {
        return new HttpClientRibbonCommandFactory(
            clientFactory,
            zuulProperties,
            zuulFallbackProviders
        );
    }
}

通过源码我们可以了解,Zuul将你自定义的fallbackprovider保存在一个Set集合中,并作为 HttpClientRibbonCommandFactory构造器的参数。

当zuul在转发请求时最终会利用 AbstractRibbonCommand进行处理。通过源码我们知道 AbstractRibbonCommand继承了 HystrixCommand,所以真正转发请求的业务逻辑是在重写 HystrixCommand类的 run方法中进行的。

具体源码如下:

代码语言:javascript
复制
@Override
    protected 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()方法,具体源码如下:

代码语言:javascript
复制
@Override
protected ClientHttpResponse getFallback() {
    if(zuulFallbackProvider != null) {
        return zuulFallbackProvider.fallbackResponse();
    }
    return super.getFallback();
}

通过源码我们知道,首先会去判断是否存在自定义的zuulFallbackProvider,如果有,那么直接回调你自定义实现类的 fallbackResponse()方法。如果不存在会走 hystrixfallback逻辑(有可能直接抛出异常)。 说到这里Zuul的降级原理大致就说完了,细心的朋友可以发现这样的一个问题,就是虽然Zuul提供了降级的回调方法 fallbackResponse(),但是这个方法是无参的,也就是说此时虽然你能够给调用端返回一个消息,但是此时你并不知道发生了什么样的异常(也就是说在这里你是获取不到异常信息的)。

Edgware.RC1版本的改进

在Edgware.RC1版本中Spring cloud zuul针对于降级进行了升级,升级的内容主要是解决上面说到的当降级出现时,怎样在降级方法中获取具体的异常信息。 增加了一个接口 FallbackProvider,这个接口继承了现有的 ZuulFallbackProvider接口,源码如下:

代码语言:javascript
复制
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()方法。下面通过源码具体了解下:

代码语言:javascript
复制
@Override
      protected ClientHttpResponse getFallback() {
          if(zuulFallbackProvider != null) {
             return getFallbackResponse();
          }
          return super.getFallback();
      }

可以看到从原来调用 zuulFallbackProvider.fallbackResponse();转而调用内部方法 getFallbackResponse()getFallbackResponse()源码如下:

代码语言:javascript
复制
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中的改进就介绍完了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-11-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序猿DD 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 如何在Zuul中使用fallback功能
  • Edgware.RC1版本的改进
相关产品与服务
微服务引擎 TSE
微服务引擎(Tencent Cloud Service Engine)提供开箱即用的云上全场景微服务解决方案。支持开源增强的云原生注册配置中心(Zookeeper、Nacos 和 Apollo),北极星网格(腾讯自研并开源的 PolarisMesh)、云原生 API 网关(Kong)以及微服务应用托管的弹性微服务平台。微服务引擎完全兼容开源版本的使用方式,在功能、可用性和可运维性等多个方面进行增强。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档