暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Feign详细构建过程及自定义扩展

逸飞兮 2019-05-24
1082

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自动配置类

  1. @Configuration

  2. @ConditionalOnClass(name = "feign.hystrix.HystrixFeign")

  3. protected static class HystrixFeignTargeterConfiguration {


  4. @Bean

  5. @ConditionalOnMissingBean

  6. public Targeter feignTargeter() {

  7. return new HystrixTargeter();

  8. }


  9. }


  10. @Configuration

  11. @ConditionalOnMissingClass("feign.hystrix.HystrixFeign")

  12. protected static class DefaultFeignTargeterConfiguration {


  13. @Bean

  14. @ConditionalOnMissingBean

  15. public Targeter feignTargeter() {

  16. return new DefaultTargeter();

  17. }


  18. }


  1. feign.hystrix.HystrixFeign类存在时,将 HystrixTargeter
    注册为 Targeter
    类型的 bean



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



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



  4. FeignClientsConfiguration


  1. @Configuration

  2. public class FeignClientsConfiguration {



  3. @Bean

  4. @ConditionalOnMissingBean

  5. public Retryer feignRetryer() {

  6. return Retryer.NEVER_RETRY;

  7. }


  8. @Bean

  9. @Scope("prototype")

  10. @ConditionalOnMissingBean

  11. public Feign.Builder feignBuilder(Retryer retryer) {

  12. return Feign.builder().retryer(retryer);

  13. }


  14. @Configuration

  15. @ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })

  16. protected static class HystrixFeignConfiguration {

  17. @Bean

  18. @Scope("prototype")

  19. @ConditionalOnMissingBean

  20. @ConditionalOnProperty(name = "feign.hystrix.enabled")

  21. public Feign.Builder feignHystrixBuilder() {

  22. return HystrixFeign.builder();

  23. }

  24. }

  25. }

重要Feign 以及内部类 Feign.Builder 都是 public 访问级别,可以注入自定义的bean。

2.EnableFeignClients与FeignClientsRegistrar类

将使用@FeignClient注解的类注册成spring bean,并使用注解中的配置

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

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

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

  4. registerDefaultConfiguration
    :注册默认的配置

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

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

  7. registerFeignClients
    :通过 registerFeignClient(BeanDefinitionRegistry,AnnotationMetadata,Map)
    方法注册每一个feignClient,过程:先获取 @FeignClient
    注解中定义的配置,将配置应用在spring bean 工厂 FeignClientFactoryBean
    , 通过工厂类 FeignClientFactoryBean
     为每一个使用 @FeignClient
    注解的类生产 FeignClient
    ,详细过程见下一节

3.FeignClientFactoryBean

FeignClient工厂bean。

  1. class FeignClientFactoryBean

  2. implements FactoryBean<Object>, InitializingBean, ApplicationContextAware{

  3. //...

  4. }

通过实现方法 FactoryBean#getObject()
来由spring框架生产FeignClient。

  1. @Override

  2. public Object getObject() throws Exception {

  3. return getTarget();

  4. }


  5. /**

  6. * 获得目标

  7. * 1. 获得FeignContext

  8. * 2. 从FeignContext中获得Feign构建器Feign.Builder

  9. * 3. 从FeignContext中获得Client,判断是否进行负载均衡

  10. * 4. 从FeignContext中获得Target,并执行Target的默认方法target(FeignClientFactoryBean, Feign.Builder,

  11. FeignContext, Target.HardCodedTarget<T>);

  12. * 5.由于一开始注入的Feign.Builder是HystrixFeign.Builder,则此处是调用HystrixFeign.Builder里的对应方法

  13. */

  14. <T> T getTarget() {

  15. FeignContext context = this.applicationContext.getBean(FeignContext.class);

  16. Feign.Builder builder = feign(context);

  17. //省略部分代码

  18. // ......

  19. Client client = getOptional(context, Client.class);

  20. if (client != null) {

  21. if (client instanceof LoadBalancerFeignClient) {

  22. // not load balancing because we have a url,

  23. // but ribbon is on the classpath, so unwrap

  24. client = ((LoadBalancerFeignClient) client).getDelegate();

  25. }

  26. builder.client(client);

  27. }

  28. Targeter targeter = get(context, Targeter.class);

  29. return (T) targeter.target(this, builder, context,

  30. new HardCodedTarget<>(this.type, this.name, url));

  31. }


  32. protected Feign.Builder feign(FeignContext context) {

  33. FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);

  34. Logger logger = loggerFactory.create(this.type);


  35. // @formatter:off

  36. Feign.Builder builder = get(context, Feign.Builder.class)

  37. // required values

  38. .logger(logger)

  39. .encoder(get(context, Encoder.class))

  40. .decoder(get(context, Decoder.class))

  41. .contract(get(context, Contract.class));

  42. // @formatter:on


  43. configureFeign(context, builder);


  44. return builder;

  45. }

工厂获得对象(目标):

  1. 1. 获得FeignContextfeign上下文)

  2. 2. FeignContext中获得Feign构建器Feign.Builderpublic,可以在此使用自定义构建器)

  3. 3. FeignContext中获得Client,判断是否进行负载均衡

  4. 4. FeignContext中获得Target,并执行Target的默认方法target(FeignClientFactoryBean, Feign.Builder,

  5. FeignContext, Target.HardCodedTarget<T>);

  6. 5. 由于一开始注入的 *Targeter* *HystrixTargeter* ,则此处是调用 HystrixTargeter 里的对应方法(从第一节的配置来看,只要 *feign.hystrix.HystrixFeign* 类存在,就是注入的 *HystrixTargeter *, 否则是 *DefaultTargeter*,对于需要**自定义构建feign的,这里不太重要**)

4.Targeter

4.1.HystrixTargeter

  1. class HystrixTargeter implements Targeter {


  2. @Override

  3. public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,

  4. FeignContext context, Target.HardCodedTarget<T> target) {

  5. // 若不是 HystrixFeign,则执行其对应的默认target方法。

  6. // 此处只处理HystrixFeign。

  7. if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {

  8. return feign.target(target);

  9. }

  10. feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;

  11. SetterFactory setterFactory = getOptional(factory.getName(), context,

  12. SetterFactory.class);

  13. if (setterFactory != null) {

  14. builder.setterFactory(setterFactory);

  15. }

  16. Class<?> fallback = factory.getFallback();

  17. if (fallback != void.class) {

  18. return targetWithFallback(factory.getName(), context, target, builder,

  19. fallback);

  20. }

  21. Class<?> fallbackFactory = factory.getFallbackFactory();

  22. if (fallbackFactory != void.class) {

  23. return targetWithFallbackFactory(factory.getName(), context, target, builder,

  24. fallbackFactory);

  25. }


  26. // 调用从Feign.Builder继承的方法。

  27. return feign.target(target);

  28. }


  29. private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,

  30. Target.HardCodedTarget<T> target, HystrixFeign.Builder builder,

  31. Class<?> fallbackFactoryClass) {

  32. FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) getFromContext(

  33. "fallbackFactory", feignClientName, context, fallbackFactoryClass,

  34. FallbackFactory.class);

  35. return builder.target(target, fallbackFactory);

  36. }


  37. private <T> T targetWithFallback(String feignClientName, FeignContext context,

  38. Target.HardCodedTarget<T> target, HystrixFeign.Builder builder,

  39. Class<?> fallback) {

  40. T fallbackInstance = getFromContext("fallback", feignClientName, context,

  41. fallback, target.type());

  42. return builder.target(target, fallbackInstance);

  43. }


  44. //...

  45. }

  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

  1. class DefaultTargeter implements Targeter {

  2. @Override

  3. public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,

  4. FeignContext context, Target.HardCodedTarget<T> target) {

  5. return feign.target(target);

  6. }

  7. }

  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。

  1. public abstract class Feign {


  2. public static Builder builder() {

  3. return new Builder();

  4. }


  5. public abstract <T> T newInstance(Target<T> target);


  6. public static class Builder {

  7. public <T> T target(Target<T> target) {

  8. return build().newInstance(target);

  9. }


  10. public Feign build() {

  11. SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =

  12. new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger, logLevel, decode404, closeAfterDecode, propagationPolicy);

  13. ParseHandlersByName handlersByName =

  14. new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,

  15. errorDecoder, synchronousMethodHandlerFactory);

  16. return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);

  17. }

  18. }

  19. }

  1. Feign.Builder#target(Target) 方法里面实际上调用的是 build() 方法来构建对象,因此重写 build() 方法即可,没有必要还重写 target(Target) 方法

  2. Feign 以及内部类 Feign.Builder 都是 public ,可以重写并注入自定义的bean

5.1.HystrixFeign

  1. public final class HystrixFeign {

  2. public static final class Builder extends Feign.Builder {

  3. @Override

  4. public Feign build() {

  5. return build(null);

  6. }


  7. // 提供一系列的target方法,支持各种配置:fallback、FallBackFactory等

  8. public <T> T target(Target<T> target, T fallback) {

  9. return build(fallback != null ? new FallbackFactory.Default<T>(fallback) : null)

  10. .newInstance(target);

  11. }


  12. public <T> T target(Target<T> target, FallbackFactory<? extends T> fallbackFactory) {

  13. return build(fallbackFactory).newInstance(target);

  14. }



  15. public <T> T target(Class<T> apiType, String url, T fallback) {

  16. return target(new Target.HardCodedTarget<T>(apiType, url), fallback);

  17. }


  18. public <T> T target(Class<T> apiType,

  19. String url,

  20. FallbackFactory<? extends T> fallbackFactory) {

  21. return target(new Target.HardCodedTarget<T>(apiType, url), fallbackFactory);

  22. }


  23. /** Configures components needed for hystrix integration. */

  24. Feign build(final FallbackFactory<?> nullableFallbackFactory) {

  25. super.invocationHandlerFactory(new InvocationHandlerFactory() {

  26. @Override

  27. public InvocationHandler create(Target target,

  28. Map<Method, MethodHandler> dispatch) {

  29. return new HystrixInvocationHandler(target, dispatch, setterFactory,

  30. nullableFallbackFactory);

  31. }

  32. });

  33. super.contract(new HystrixDelegatingContract(contract));

  34. return super.build();

  35. }

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

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

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

5.2示例

以下示例参考 SentinelFeign

  1. @Override

  2. public Feign build() {

  3. super.invocationHandlerFactory(new InvocationHandlerFactory() {

  4. @Override

  5. public InvocationHandler create(Target target,

  6. Map<Method, MethodHandler> dispatch) {

  7. // using reflect get fallback and fallbackFactory properties from

  8. // FeignClientFactoryBean because FeignClientFactoryBean is a package

  9. // level class, we can not use it in our package

  10. Object feignClientFactoryBean = Builder.this.applicationContext

  11. .getBean("&" + target.type().getName());


  12. Class fallback = (Class) getFieldValue(feignClientFactoryBean,

  13. "fallback");

  14. Class fallbackFactory = (Class) getFieldValue(feignClientFactoryBean,

  15. "fallbackFactory");

  16. String name = (String) getFieldValue(feignClientFactoryBean, "name");


  17. Object fallbackInstance;

  18. FallbackFactory fallbackFactoryInstance;

  19. // check fallback and fallbackFactory properties

  20. // 以下逻辑在HystrixTargeter中有,但执行自定义的builder,不会执行到那段逻辑,因此此处加上。

  21. if (void.class != fallback) {

  22. fallbackInstance = getFromContext(name, "fallback", fallback,

  23. target.type());

  24. return new PegasusInvocationHandler(target, dispatch, setterFactory,

  25. new FallbackFactory.Default(fallbackInstance));

  26. }

  27. if (void.class != fallbackFactory) {

  28. fallbackFactoryInstance = (FallbackFactory) getFromContext(name,

  29. "fallbackFactory", fallbackFactory,

  30. FallbackFactory.class);

  31. return new PegasusInvocationHandler(target, dispatch, setterFactory,

  32. fallbackFactoryInstance);

  33. }

  34. // 此处还是会使用一个默认的FallbackFactory。

  35. return new PegasusInvocationHandler(target, dispatch, setterFactory, new PegasusFeignFallbackFactory<>(target));

  36. }


  37. private Object getFromContext(String name, String type,

  38. Class fallbackType, Class targetType) {

  39. Object fallbackInstance = feignContext.getInstance(name,

  40. fallbackType);

  41. if (fallbackInstance == null) {

  42. throw new IllegalStateException(String.format(

  43. "No %s instance of type %s found for feign client %s",

  44. type, fallbackType, name));

  45. }


  46. if (!targetType.isAssignableFrom(fallbackType)) {

  47. throw new IllegalStateException(String.format(

  48. "Incompatible %s instance. Fallback/fallbackFactory of type %s is not assignable to %s for feign client %s",

  49. type, fallbackType, targetType, name));

  50. }

  51. return fallbackInstance;

  52. }

  53. });


  54. super.contract(new HystrixDelegatingContract(contract));

  55. return super.build();

  56. }

需要自定义fallbackFactory,则实现 feign.hystrix.FallbackFactory类,需要自定义fallback,则实现 org.springframework.cglib.proxy.MethodInterceptor即可

6.总结

  1. 由于Feign构建过程所用到的 Targeter 是 package 访问级别的,不能使用自定义的

  2. Feign以及Feign.Builder是 publilc,给了我们扩展的空间。

7.参考资料

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

  2. spring-cloud-alibaba-sentinel-0.9.0.RELEASE.jar中的 sentinelFeign 实现

  3. Spring Cloud Alibaba Sentinel 整合 Feign 的设计实现


文章转载自逸飞兮,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论