国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

HystrixFeign的詳細構建過程及自定義擴展功能

曹金海 / 3629人閱讀

摘要:重要以及內部類都是訪問級別,可以注入自定義的。的目的是將包裝成風格以便開發。示例以下示例參考其中的和是自定義的。需要自定義,則實現類,需要自定義,則實現即可總結由于構建過程所用到的是訪問級別的,不能使用自定義的以及是,給了我們擴展的空間。

spring-cloud-openfeign-core-2.1.1.RELEASE.jarHystrixFeign 的詳細構建過程:

@EnableFeignClients -> FeignClientsRegistrar 掃描 @Feign注解的類 -> FeignClientFactoryBean通過Targeter生產FeignClient -> Targeter通過Feign.Builder構建Feign -> Feign.Builder

1. 準備工作(配置)

FeignAutoConfiguration自動配置類

    @Configuration
    @ConditionalOnClass(name = "feign.hystrix.HystrixFeign")
    protected static class HystrixFeignTargeterConfiguration {

        @Bean
        @ConditionalOnMissingBean
        public Targeter feignTargeter() {
            return new HystrixTargeter();
        }

    }

    @Configuration
    @ConditionalOnMissingClass("feign.hystrix.HystrixFeign")
    protected static class DefaultFeignTargeterConfiguration {

        @Bean
        @ConditionalOnMissingBean
        public Targeter feignTargeter() {
            return new DefaultTargeter();
        }

    }

feign.hystrix.HystrixFeign類存在時,將 HystrixTargeter 注冊為 Targeter 類型的 bean

feign.hystrix.HystrixFeign類不存在時,使用 DefaultTargeter 。

看起來似乎可以使用自定義的Targeter代替Hystrix或默認的,這樣就可以自定義各種功能了。實際上不行,因為 Targeterpackage 訪問級別的。

FeignClientsConfiguration

@Configuration
public class FeignClientsConfiguration {
    
            
    @Bean
    @ConditionalOnMissingBean
    public Retryer feignRetryer() {
        return Retryer.NEVER_RETRY;
    }

    @Bean
    @Scope("prototype")
    @ConditionalOnMissingBean
    public Feign.Builder feignBuilder(Retryer retryer) {
        return Feign.builder().retryer(retryer);
    }
    
    @Configuration
    @ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
    protected static class HystrixFeignConfiguration {
        @Bean
        @Scope("prototype")
        @ConditionalOnMissingBean
        @ConditionalOnProperty(name = "feign.hystrix.enabled")
        public Feign.Builder feignHystrixBuilder() {
            return HystrixFeign.builder();
        }
    }
}

重要Feign 以及內部類 Feign.Builder 都是 public 訪問級別,可以注入自定義的bean。

2.EnableFeignClients與FeignClientsRegistrar類

將使用@FeignClient注解的類注冊成spring bean,并使用注解中的配置

在@EnableFeignClients注解中導入FeignClientsRegistrar類

FeignClientsRegistrar類實現了ImportBeanDefinitionRegistrar類,會由spring框架執行實現方法 registerBeanDefinitions(AnnotationMetaData, BeanDefinitionRegistry)

FeignClientsRegistrar中的 registerBeanDefinitions方法調用兩個方法

registerDefaultConfiguration:注冊默認的配置

registerFeignClients:注冊Feign客戶端(重點

registerFeignClients:獲取 @EnableFeignClients注解中定義的配置掃描feign客戶端

registerFeignClients:通過registerFeignClient(BeanDefinitionRegistry, AnnotationMetadata, Map)方法注冊每一個feignClient,過程:先獲取 @FeignClient注解中定義的配置,將配置應用在spring bean 工廠 FeignClientFactoryBean, 通過工廠類 FeignClientFactoryBean 為每一個使用@FeignClient注解的類生產 FeignClient,詳細過程見下一節

3.FeignClientFactoryBean

FeignClient工廠bean。

class FeignClientFactoryBean
    implements FactoryBean, InitializingBean, ApplicationContextAware{
    //...
}

通過實現方法 FactoryBean#getObject()來由spring框架生產FeignClient。

@Override
public Object getObject() throws Exception {
    return getTarget();
}

/**
 * 獲得目標
 * 1. 獲得FeignContext
 * 2. 從FeignContext中獲得Feign構建器Feign.Builder
 * 3. 從FeignContext中獲得Client,判斷是否進行負載均衡
 * 4. 從FeignContext中獲得Target,并執行Target的默認方法target(FeignClientFactoryBean, Feign.Builder,
            FeignContext, Target.HardCodedTarget);
 * 5.由于一開始注入的Feign.Builder是HystrixFeign.Builder,則此處是調用HystrixFeign.Builder里的對應方法
 */
 T getTarget() {
    FeignContext context = this.applicationContext.getBean(FeignContext.class);
    Feign.Builder builder = feign(context);
    //省略部分代碼
    // ......
    Client client = getOptional(context, Client.class);
    if (client != null) {
        if (client instanceof LoadBalancerFeignClient) {
            // not load balancing because we have a url,
            // but ribbon is on the classpath, so unwrap
            client = ((LoadBalancerFeignClient) client).getDelegate();
        }
        builder.client(client);
    }
    Targeter targeter = get(context, Targeter.class);
    return (T) targeter.target(this, builder, context,
        new HardCodedTarget<>(this.type, this.name, url));
}

    protected Feign.Builder feign(FeignContext context) {
        FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
        Logger logger = loggerFactory.create(this.type);

        // @formatter:off
        Feign.Builder builder = get(context, Feign.Builder.class)
                // required values
                .logger(logger)
                .encoder(get(context, Encoder.class))
                .decoder(get(context, Decoder.class))
                .contract(get(context, Contract.class));
        // @formatter:on

        configureFeign(context, builder);

        return builder;
    }

工廠獲得對象(目標):

1. 獲得FeignContext(feign上下文)
2. 從FeignContext中獲得Feign構建器Feign.Builder(public,可以在此使用自定義構建器)
3. 從FeignContext中獲得Client,判斷是否進行負載均衡
4. 從FeignContext中獲得Target,并執行Target的默認方法target(FeignClientFactoryBean, Feign.Builder,
  FeignContext, Target.HardCodedTarget);
5. 由于一開始注入的 *Targeter* 是 *HystrixTargeter* ,則此處是調用 HystrixTargeter 里的對應方法(從第一節的配置來看,只要 *feign.hystrix.HystrixFeign* 類存在,就是注入的 *HystrixTargeter *, 否則是 *DefaultTargeter*,對于需要**自定義構建feign的,這里不太重要**)


4.Targeter 4.1.HystrixTargeter
class HystrixTargeter implements Targeter {

    @Override
    public  T target(FeignClientFactoryBean factory, Feign.Builder feign,
            FeignContext context, Target.HardCodedTarget target) {
        // 若不是 HystrixFeign,則執行其對應的默認target方法。
        // 此處只處理HystrixFeign。
        if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
            return feign.target(target);
        }
        feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
        SetterFactory setterFactory = getOptional(factory.getName(), context,
                SetterFactory.class);
        if (setterFactory != null) {
            builder.setterFactory(setterFactory);
        }
        Class fallback = factory.getFallback();
        if (fallback != void.class) {
            return targetWithFallback(factory.getName(), context, target, builder,
                    fallback);
        }
        Class fallbackFactory = factory.getFallbackFactory();
        if (fallbackFactory != void.class) {
            return targetWithFallbackFactory(factory.getName(), context, target, builder,
                    fallbackFactory);
        }

        // 調用從Feign.Builder繼承的方法。
        return feign.target(target);
    }
    
        private  T targetWithFallbackFactory(String feignClientName, FeignContext context,
            Target.HardCodedTarget target, HystrixFeign.Builder builder,
            Class fallbackFactoryClass) {
        FallbackFactory fallbackFactory = (FallbackFactory) getFromContext(
                "fallbackFactory", feignClientName, context, fallbackFactoryClass,
                FallbackFactory.class);
        return builder.target(target, fallbackFactory);
    }

    private  T targetWithFallback(String feignClientName, FeignContext context,
            Target.HardCodedTarget target, HystrixFeign.Builder builder,
            Class fallback) {
        T fallbackInstance = getFromContext("fallback", feignClientName, context,
                fallback, target.type());
        return builder.target(target, fallbackInstance);
    }
    
    //...
}

HystrixTarget只處理 Feign.Builder 類型為 feign.hystrix.HystrixFeign.Builder

若feign構建器不是 feign.hystrix.HystrixFeign.Builder 類型,則執行注入的 feign 構建器的默認target方法

因此,即使注入的 Targeter 是 HystrixTargeter,此處也可以執行自定義 Feign.Builder

理解:Feign.Builder#target(Target) 方法通常不會被 override(后續會講解為什么不重寫此方法)

4.2.DefaultTargeter
class DefaultTargeter implements Targeter {
    @Override
    public  T target(FeignClientFactoryBean factory, Feign.Builder feign,
            FeignContext context, Target.HardCodedTarget target) {
        return feign.target(target);
    }
}

執行 Feign.Builder (子)類型對應的 默認 target方法。

理解:Feign.Builder#target(Target) 方法通常不會被 override(后續會講解為什么不重寫此方法)

5.FeignBuilder

feign構建器:構建feign對象。

Feign的目的是將 http api 包裝成 restful 風格以便開發。

在實現中,Feign 是一個為目標http apis 生成 feign對象(Feign#newInstance)的工廠。

上述步驟目前需要的都是通過對應的 Builder 構建對應的Feign。

public abstract class Feign {

  public static Builder builder() {
    return new Builder();
  }
   
  public abstract  T newInstance(Target target);
  
  public static class Builder {
    public  T target(Target target) {
      return build().newInstance(target);
    }

    public Feign build() {
      SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
          new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger, logLevel, decode404, closeAfterDecode, propagationPolicy);
      ParseHandlersByName handlersByName =
          new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
              errorDecoder, synchronousMethodHandlerFactory);
      return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
    }
  }
}

Feign.Builder#target(Target) 方法里面實際上調用的是 build() 方法來構建對象,因此重寫 build() 方法即可,沒有必要還重寫 target(Target) 方法

Feign 以及內部類 Feign.Builder 都是 public可以重寫并注入自定義的bean

5.1.HystrixFeign
public final class HystrixFeign {
  public static final class Builder extends Feign.Builder {  
    @Override
    public Feign build() {
      return build(null);
    }
    
    // 提供一系列的target方法,支持各種配置:fallback、FallBackFactory等
    public  T target(Target target, T fallback) {
      return build(fallback != null ? new FallbackFactory.Default(fallback) : null)
          .newInstance(target);
    }

    public  T target(Target target, FallbackFactory fallbackFactory) {
      return build(fallbackFactory).newInstance(target);
    }
      
    
    public  T target(Class apiType, String url, T fallback) {
      return target(new Target.HardCodedTarget(apiType, url), fallback);
    }

    public  T target(Class apiType,
                        String url,
                        FallbackFactory fallbackFactory) {
      return target(new Target.HardCodedTarget(apiType, url), fallbackFactory);
    }

    /** Configures components needed for hystrix integration. */
    Feign build(final FallbackFactory nullableFallbackFactory) {
      super.invocationHandlerFactory(new InvocationHandlerFactory() {
        @Override
        public InvocationHandler create(Target target,
                                        Map dispatch) {
          return new HystrixInvocationHandler(target, dispatch, setterFactory,
              nullableFallbackFactory);
        }
      });
      super.contract(new HystrixDelegatingContract(contract));
      return super.build();
    }

基本到了這一步,需要設置的東西,都可以配置了。

雖然 build 方法中涉及到 InvocationHandler,但基本不需要改什么,而 InvocationHandler 竟然也是 package 訪問級別,所以只好復制一個,使用自己的。

HystrixDelegatingContract 是 public 級別,不需要修改的話,仍然用這個。

5.2示例

以下示例參考 SentinelFeign
其中的 YiFeiXiInvocationHandlerYiFeiXiFeignFallbackFactory是自定義的。

@Override
public Feign build() {
    super.invocationHandlerFactory(new InvocationHandlerFactory() {
        @Override
        public InvocationHandler create(Target target,
                                        Map dispatch) {
            // using reflect get fallback and fallbackFactory properties from
            // FeignClientFactoryBean because FeignClientFactoryBean is a package
            // level class, we can not use it in our package
            Object feignClientFactoryBean = Builder.this.applicationContext
                .getBean("&" + target.type().getName());

            Class fallback = (Class) getFieldValue(feignClientFactoryBean,
                                                   "fallback");
            Class fallbackFactory = (Class) getFieldValue(feignClientFactoryBean,
                                                          "fallbackFactory");
            String name = (String) getFieldValue(feignClientFactoryBean, "name");

            Object fallbackInstance;
            FallbackFactory fallbackFactoryInstance;
            // check fallback and fallbackFactory properties
            // 以下邏輯在HystrixTargeter中有,但執行自定義的builder,不會執行到那段邏輯,因此此處加上。
            if (void.class != fallback) {
                fallbackInstance = getFromContext(name, "fallback", fallback,
                                                  target.type());
                return new YiFeiXiInvocationHandler(target, dispatch, setterFactory,
                                                    new FallbackFactory.Default(fallbackInstance));
            }
            if (void.class != fallbackFactory) {
                fallbackFactoryInstance = (FallbackFactory) getFromContext(name,
                                                                           "fallbackFactory", fallbackFactory,
                                                                           FallbackFactory.class);
                return new YiFeiXiInvocationHandler(target, dispatch, setterFactory,
                                                    fallbackFactoryInstance);
            }
            // 若注解中沒有使用fallback或fallbackFactory,則使用一個默認的FallbackFactory。
            return new YiFeiXiInvocationHandler(target, dispatch, setterFactory, new YiFeiXiFeignFallbackFactory<>(target));
        }

        private Object getFromContext(String name, String type,
                                      Class fallbackType, Class targetType) {
            Object fallbackInstance = feignContext.getInstance(name,
                                                               fallbackType);
            if (fallbackInstance == null) {
                throw new IllegalStateException(String.format(
                    "No %s instance of type %s found for feign client %s",
                    type, fallbackType, name));
            }

            if (!targetType.isAssignableFrom(fallbackType)) {
                throw new IllegalStateException(String.format(
                    "Incompatible %s instance. Fallback/fallbackFactory of type %s is not assignable to %s for feign client %s",
                    type, fallbackType, targetType, name));
            }
            return fallbackInstance;
        }
    });

    super.contract(new HystrixDelegatingContract(contract));
    return super.build();
}

需要自定義fallbackFactory,則實現 feign.hystrix.FallbackFactory類,需要自定義fallback,則實現 org.springframework.cglib.proxy.MethodInterceptor即可

6.總結

由于Feign構建過程所用到的 Targeterpackage 訪問級別的,不能使用自定義的

Feign以及Feign.Builderpublilc,給了我們擴展的空間。

7.參考資料

feign-hystrix-10.1.0.jarspring-cloud-openfeign-core-2.1.1.RELEASE.jar

spring-cloud-alibaba-sentinel-0.9.0.RELEASE.jar中的 sentinelFeign 實現

Spring Cloud Alibaba Sentinel 整合 Feign 的設計實現

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/74639.html

相關文章

  • Spring Cloud Alibaba Sentinel 整合 Feign 設計實現

    摘要:作用跟一致跟屬性作用一致給設置注解絕對路徑,用于替換服務名。在服務名或與之間默認是,表示當前這個生成的是否是。內部的能獲取服務名信息,的實現類能拿到對應的請求路徑信息。很不幸,這個類也是包級別的類。整合的代碼目前已經在倉庫上,但是沒未發版。 作者 | Spring Cloud Alibaba 高級開發工程師洛夜來自公眾號阿里巴巴中間件投稿 前段時間 Hystrix 宣布不再維護之后(H...

    OldPanda 評論0 收藏0
  • spring-cloud-feign源碼深度解析

    摘要:內部使用了的動態代理為目標接口生成了一個動態代理類,這里會生成一個動態代理原理統一的方法攔截器,同時為接口的每個方法生成一個攔截器,并解析方法上的元數據,生成一個請求模板。的核心源碼解析到此結束了,不知道是否對您有無幫助,可留言跟我交流。 Feign是一個聲明式的Web服務客戶端。這使得Web服務客戶端的寫入更加方便 要使用Feign創建一個界面并對其進行注釋。它具有可插拔注釋支持,包...

    vibiu 評論0 收藏0
  • 微信二次分享

    摘要:接下來通過詳細的步驟介紹如何接入微信二次分享操作。不要嘗試在中使用異步請求修改本次分享的內容,因為客戶端分享操作是一個同步操作,這時候使用的回包會還沒有返回用戶點擊分享到朋友圈已分享已取消此時微信二次分享就已經大功告成了。 微信二次分享 效果演示 showImg(https://segmentfault.com/img/remote/1460000016895951); 如何運行項目 ...

    Betta 評論0 收藏0
  • 微信二次分享

    摘要:接下來通過詳細的步驟介紹如何接入微信二次分享操作。不要嘗試在中使用異步請求修改本次分享的內容,因為客戶端分享操作是一個同步操作,這時候使用的回包會還沒有返回用戶點擊分享到朋友圈已分享已取消此時微信二次分享就已經大功告成了。 微信二次分享 效果演示 showImg(https://segmentfault.com/img/remote/1460000016895951); 如何運行項目 ...

    NusterCache 評論0 收藏0
  • 微信二次分享

    摘要:接下來通過詳細的步驟介紹如何接入微信二次分享操作。不要嘗試在中使用異步請求修改本次分享的內容,因為客戶端分享操作是一個同步操作,這時候使用的回包會還沒有返回用戶點擊分享到朋友圈已分享已取消此時微信二次分享就已經大功告成了。 微信二次分享 效果演示 showImg(https://segmentfault.com/img/remote/1460000016895951); 如何運行項目 ...

    Kahn 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<