千家信息网

Feign如何构建以及实现自定义扩展功能

发表于:2025-01-16 作者:千家信息网编辑
千家信息网最后更新 2025年01月16日,小编给大家分享一下Feign如何构建以及实现自定义扩展功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!spring-cl
千家信息网最后更新 2025年01月16日Feign如何构建以及实现自定义扩展功能

小编给大家分享一下Feign如何构建以及实现自定义扩展功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

spring-cloud-openfeign-core-2.1.1.RELEASE.jarHystrixFeign 的详细构建过程:

@EnableFeignClients -> FeignClientsRegistrar 扫描 @Feign注解的类 -> FeignClientFactoryBean通过Targeter生产FeignClient -> Targeter通过Feign.Builder构建Feign -> Feign.Builder

1. 准备工作(配置)

  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();        }    }
  1. feign.hystrix.HystrixFeign类存在时,将 HystrixTargeter 注册为 Targeter 类型的 bean

  2. feign.hystrix.HystrixFeign类不存在时,使用 DefaultTargeter

  3. 看起来似乎可以使用自定义的Targeter代替Hystrix或默认的,这样就可以自定义各种功能了。实际上不行,因为 Targeterpackage 访问级别的。

  4. FeignClientsConfiguration

@Configurationpublic 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,并使用注解中的配置

  1. 在@EnableFeignClients注解中导入FeignClientsRegistrar类

  2. FeignClientsRegistrar类实现了ImportBeanDefinitionRegistrar类,会由spring框架执行实现方法 registerBeanDefinitions(AnnotationMetaData, BeanDefinitionRegistry)

  3. FeignClientsRegistrar中的 registerBeanDefinitions方法调用两个方法

    1. registerDefaultConfiguration:注册默认的配置

    2. registerFeignClients:注册Feign客户端(重点

  4. registerFeignClients:获取 @EnableFeignClients注解中定义的配置扫描feign客户端

  5. 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。

@Overridepublic 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);    }    //...}
  1. HystrixTarget只处理 Feign.Builder 类型为 feign.hystrix.HystrixFeign.Builder

  2. 若feign构建器不是 feign.hystrix.HystrixFeign.Builder 类型,则执行注入的 feign 构建器的默认target方法

  3. 因此,即使注入的 Targeter 是 HystrixTargeter,此处也可以执行自定义 Feign.Builder

  4. 理解: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);    }}
  1. 执行 Feign.Builder (子)类型对应的 默认 target方法。

  2. 理解: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);    }  }}
  1. Feign.Builder#target(Target) 方法里面实际上调用的是 build() 方法来构建对象,因此重写 build() 方法即可,没有必要还重写 target(Target) 方法

  2. 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();    }

基本到了这一步,需要设置的东西,都可以配置了。

  1. 虽然 build 方法中涉及到 InvocationHandler,但基本不需要改什么,而 InvocationHandler 竟然也是 package 访问级别,所以只好复制一个,使用自己的。

  2. HystrixDelegatingContract 是 public 级别,不需要修改的话,仍然用这个。

5.2示例

以下示例参考 SentinelFeign
其中的 YiFeiXiInvocationHandlerYiFeiXiFeignFallbackFactory是自定义的。

@Overridepublic 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即可

以上是"Feign如何构建以及实现自定义扩展功能"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

0