美文网首页
SpringCloud解析六:Feign解析上

SpringCloud解析六:Feign解析上

作者: 一根线条 | 来源:发表于2020-01-08 14:57 被阅读0次

一:使用方法

1,添加依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath />
</parent>
<properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
</properties>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.2.0.RELEASE</version>
</dependency>

2,在springboot的启动类上面添加注解

@SpringBootApplication
//当程序启动时会扫描所有带有@FeignClient注解的类进行处理
@EnableFeignClients
public class Application 
{
    public static void main( String[] args) {
        SpringApplication.run(Application.class, args)  ;
    }
}

3,添加配置

server.port=8011
spring.application.name=feign-app

#开启okhttp为feign的默认Client
feign.httpclient.enable=false
feign.okhttp.enable=true

feign.client.config.<feignName>.connectTimeout=5000 #连接超时时间
feign.client.config.<feignName>.readTimeout=5000 #读超时时间
feign.client.config.<feignName>.loggerLevel=full  #Feign的日志级别

feign.clinet.config.default.connectTimeout=5000
feign.clinet.config.default.readTimeout=5000
feign.clinet.config.default.loggerLevel=full

ribbon.ConnectTimeout=30000  #请求连接的超时时间
ribbon.ReadTimeout=120000  #请求处理的超时时间

feign.httpclient.enabled=true
feign.okhttp.enabled=false

feign.hystrix.enabled=true #hystrix熔断机制
hystrix.shareSecurityContext=true
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=100000
hystrix.command.default.circuitBreaker.forceClosed=true
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=600000

4,添加Feign客户端

/**
 * name : 指定Feign的名称。如果使用了Ribbon,该属性会作为微服务名称用户服务发现
 * path: 定义统一的前缀
 * url: 一般用于调试,手动指定调用的地址
 * */
@FeignClient(name="hostNmae" )
public interface FeginClientService {
    
    @RequestMapping(method=RequestMethod.GET,path= {"/route/balance/access/query"})
    public String getMsg() ;
}

二:源码分析

1,@EnableFeignClients

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
    /**
     * @return the array of 'basePackages'.
     */
    String[] value() default {};
    /**
     * Base packages to scan for annotated components.
     * @return the array of 'basePackages'.
     */
    String[] basePackages() default {};
    /**
     * @return the array of 'basePackageClasses'.
     */
    Class<?>[] basePackageClasses() default {};
    /**
     * @see FeignClientsConfiguration for the defaults
     * @return list of default configurations
     */
    Class<?>[] defaultConfiguration() default {};
    /**
     * List of classes annotated with @FeignClient. If not empty, disables classpath
     */
    Class<?>[] clients() default {};
}

该注解会导入FeignClientsRegistrar类进行FeginClient的配置,其代码如下

class FeignClientsRegistrar
        implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    private ResourceLoader resourceLoader;
    private Environment environment;
    FeignClientsRegistrar() {
    }
    //被初始化调用
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,
            BeanDefinitionRegistry registry) {
        //基于注解添加默认的配置。由于在@EnableFeignClients并未设置,所以方法内并不会真正执行某些动作
        registerDefaultConfiguration(metadata, registry);
        //基于注解配置每个Feign客户端
        registerFeignClients(metadata, registry);
    }
    private void registerDefaultConfiguration(AnnotationMetadata metadata,
            BeanDefinitionRegistry registry) {
        Map<String, Object> defaultAttrs = metadata
                .getAnnotationAttributes(EnableFeignClients.class.getName(), true);

        if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
            String name;
            if (metadata.hasEnclosingClass()) {
                name = "default." + metadata.getEnclosingClassName();
            } else {
                name = "default." + metadata.getClassName();
            }
            //注册默认的Feign客户端配置
            registerClientConfiguration(registry, name,
                    defaultAttrs.get("defaultConfiguration"));
        }
    }

    public void registerFeignClients(AnnotationMetadata metadata,
            BeanDefinitionRegistry registry) {
        ClassPathScanningCandidateComponentProvider scanner = getScanner();
        scanner.setResourceLoader(this.resourceLoader);

        Set<String> basePackages;

        Map<String, Object> attrs = metadata
                .getAnnotationAttributes(EnableFeignClients.class.getName());
        //设置注解的过滤器,筛选出@FeignClient
        AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
                FeignClient.class);
        final Class<?>[] clients = attrs == null ? null
                : (Class<?>[]) attrs.get("clients");
        if (clients == null || clients.length == 0) {
            /**
            * 如果在@FeignClients中没有配置FeignClient,设置过滤器并得到@EnableFeignClients中value、
            * basePackages、basePackageClasses属性的取值并放入集合,如果集合为空,
            * 则返回@FeignClients注解所在的包路径
            */
            scanner.addIncludeFilter(annotationTypeFilter);
            basePackages = getBasePackages(metadata);
        } else {
            //用@FeignClient注释的类列表,如果不为空,则禁用类路径扫描。
            final Set<String> clientClasses = new HashSet<>();
            basePackages = new HashSet<>();
            //遍历@FeignClients中配置的各个客户端
            for (Class<?> clazz : clients) {
                //添加各个Feign客户端的包路径
                basePackages.add(ClassUtils.getPackageName(clazz));
                clientClasses.add(clazz.getCanonicalName());
            }
            AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
                @Override
                protected boolean match(ClassMetadata metadata) {
                    String cleaned = metadata.getClassName().replaceAll("\\$", ".");
                    return clientClasses.contains(cleaned);
                }
            };
            scanner.addIncludeFilter(
                    new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
        }

        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidateComponents = scanner
                    .findCandidateComponents(basePackage);
            for (BeanDefinition candidateComponent : candidateComponents) {
                if (candidateComponent instanceof AnnotatedBeanDefinition) {
                    // verify annotated class is an interface
                    AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
                    AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
                    Assert.isTrue(annotationMetadata.isInterface(),
                            "@FeignClient can only be specified on an interface");

                    Map<String, Object> attributes = annotationMetadata
                            .getAnnotationAttributes(
                                    FeignClient.class.getCanonicalName());

                    String name = getClientName(attributes);
                    //添加每个Fegin客户端的配置信息
                    registerClientConfiguration(registry, name,
                            attributes.get("configuration"));
                    //注册每个Fegin客户端
                    registerFeignClient(registry, annotationMetadata, attributes);
                }
            }
        }
    }

    private void registerFeignClient(BeanDefinitionRegistry registry,
            AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
        String className = annotationMetadata.getClassName();
        //这里是重点,当执行注入的时候会被调用,定义Bean的工厂[见下面的源码]
        BeanDefinitionBuilder definition = BeanDefinitionBuilder
                .genericBeanDefinition(FeignClientFactoryBean.class);
        validate(attributes);
        definition.addPropertyValue("url", getUrl(attributes));
        definition.addPropertyValue("path", getPath(attributes));
        //依次获取serviceId、name、value的值,取到第一个不为空为止
        String name = getName(attributes);
        definition.addPropertyValue("name", name);
        //ApplicationContext的标识【从FeignContext中得到该客户端的应用上下文】。
        //首先获取注解上的contextId属性,没有则依次获取serviceId、name、value的值
        String contextId = getContextId(attributes);
        definition.addPropertyValue("contextId", contextId);
        definition.addPropertyValue("type", className);
        definition.addPropertyValue("decode404", attributes.get("decode404"));
        definition.addPropertyValue("fallback", attributes.get("fallback"));
        definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        //别名
        String alias = contextId + "FeignClient";
        AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();

        boolean primary = (Boolean) attributes.get("primary"); // has a default, won't be
                                                                // null

        beanDefinition.setPrimary(primary);

        String qualifier = getQualifier(attributes);
        if (StringUtils.hasText(qualifier)) {
            alias = qualifier;
        }

        //持有BeanDefinition、BeanDefinition的名称,BeanDefinition的别名
        BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
                new String[] { alias });
        BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
    }
}

到此为止,主要完成了几件事
1)读取@EnableFeignClients中配置的全局Fegin客户端的默认配置(defaultConfiguration),并生成名为“.default”开头,类名(配置类全路径)结尾的FeignClientSpecification实例Bean
2)读取@EnableFeignClients中配置的clients属性,如果为空则扫描value或basePackages或basePackageClasses属性指定的类路径得到使用@FeignClient注解标注的接口; 否则遍历每个clients,将每个client的包路径收集起来作为basePackages,然后再扫描一次这些路径得到指定的这些clients【@FeignClient标注的接口】
3)解析每个@FeignClient标注的接口,获取@FeignClient的configuration值(可能为空),然后生成FeignClientSpecification实例Bean(其Bean的名称为@FeignClient中contextId或value或name或serviceId的值); 同时为该@FeignClient标注的接口创建FeignClientFactoryBean实例对(其Bean的名字为配置的qualifier属性,如果该属性为空则以属性contextId或serviceId或name或value的值【如果为http开头的url则只取host】开头,以“FeignClient”结尾的字符串作为Bean的名字。

注意:该FeignClientFactoryBean工厂实例是运行时的核心。

FeignClientFactoryBean【源码摘选】
通过此类我们可以看到被注入的Feign客户端被封装成了什么样。

class FeignClientFactoryBean
        implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
    @Override
    public Object getObject() throws Exception {
        return getTarget();
    }

    //从this.contextId所指定名称的ApplicationContext中得到类型为type的Bean
    protected <T> T getOptional(FeignContext context, Class<T> type) {
        return context.getInstance(this.contextId, type);
    }

    /**
     * @param <T> the target type of the Feign client
     * @return a {@link Feign} client created with the specified data and the context information
     */
    <T> T getTarget() {
        //从当前应用的ApplicationContext中得到 FeignContext 实例bean
        //FeignContext 中保存了每个Feign客户端对应的ApplicationContext,在自动配置类FeignAutoConfiguration中创建(后面解析)
        FeignContext context = this.applicationContext.getBean(FeignContext.class);
        //得到Fegin的构建器
        Feign.Builder builder = feign(context);

        //从这里可见,
        if (!StringUtils.hasText(this.url)) { //如果url的值为空
            if (!this.name.startsWith("http")) {  //如果name不是以http开头
                this.url = "http://" + this.name;
            }
            else {
                this.url = this.name;
            }
            //添加上path部分
            this.url += cleanPath();
            //得到具备负载均衡能力的Feigin客户端
            return (T) loadBalance(builder, context,
                    new HardCodedTarget<>(this.type, this.name, this.url));
        }
        if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
            this.url = "http://" + this.url;
        }
        //添加上path部分
        String url = this.url + cleanPath();
        //从FeginContext中得到Client类型的Bean【从名为this.contextId的ApplicationContext中得到类型为type的Bean】
        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对象设值
            builder.client(client);
        }
        //从FeginContext中得到Targeter类型的Bean
        Targeter targeter = get(context, Targeter.class);
        return (T) targeter.target(this, builder, context,
                new HardCodedTarget<>(this.type, this.name, url));
    }

    protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
            HardCodedTarget<T> target) {
        // 从FeignContext中得到Client类型的Bean【从this.contextId指定名称的ApplicationContext中得到类型为type的Bean】。
        // 该实例在FeignRibbonClientAutoConfiguration配置中引入的HttpClientFeignLoadBalancedConfiguration配置类中进行了配置
        // 默认是底层使用Apache HttpClient封装的LoadBalancerFeignClient对象
        // 在LoadBalancerFeignClient内部使用Ribbon的SpringClientFactory来完成某些操作,从而实现与Ribbo的集成
        Client client = getOptional(context, Client.class);
        if (client != null) {
            //设置Client的值
            builder.client(client);
            //从FeignContext中得到Client类型的Bean【从this.contextId指定名称的ApplicationContext中得到类型为type的Bean】。
            //HystrixTargeter、DefaultTargeter【在FeignAutoConfiguration中配置】
            Targeter targeter = get(context, Targeter.class);
            //返回目标对象【源码见下面】
            return targeter.target(this, builder, context, target);
        }
        throw new IllegalStateException(
                "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
    }

    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;
    }

    protected void configureFeign(FeignContext context, Feign.Builder builder) {
        FeignClientProperties properties = this.applicationContext
                .getBean(FeignClientProperties.class);
        if (properties != null) {
            if (properties.isDefaultToProperties()) {
                configureUsingConfiguration(context, builder);
                configureUsingProperties(
                        properties.getConfig().get(properties.getDefaultConfig()),
                        builder);
                configureUsingProperties(properties.getConfig().get(this.contextId),
                        builder);
            }
            else {
                configureUsingProperties(
                        properties.getConfig().get(properties.getDefaultConfig()),
                        builder);
                configureUsingProperties(properties.getConfig().get(this.contextId),
                        builder);
                configureUsingConfiguration(context, builder);
            }
        }
        else {
            configureUsingConfiguration(context, builder);
        }
    }

    protected void configureUsingConfiguration(FeignContext context,
            Feign.Builder builder) {
        Logger.Level level = getOptional(context, Logger.Level.class);
        if (level != null) {
            builder.logLevel(level);
        }
        Retryer retryer = getOptional(context, Retryer.class);
        if (retryer != null) {
            builder.retryer(retryer);
        }
        ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class);
        if (errorDecoder != null) {
            builder.errorDecoder(errorDecoder);
        }
        Request.Options options = getOptional(context, Request.Options.class);
        if (options != null) {
            builder.options(options);
        }
        Map<String, RequestInterceptor> requestInterceptors = context
                .getInstances(this.contextId, RequestInterceptor.class);
        if (requestInterceptors != null) {
            builder.requestInterceptors(requestInterceptors.values());
        }
        QueryMapEncoder queryMapEncoder = getOptional(context, QueryMapEncoder.class);
        if (queryMapEncoder != null) {
            builder.queryMapEncoder(queryMapEncoder);
        }
        if (this.decode404) {
            builder.decode404();
        }
    }

    protected void configureUsingProperties(
            FeignClientProperties.FeignClientConfiguration config,
            Feign.Builder builder) {
        if (config == null) {
            return;
        }

        if (config.getLoggerLevel() != null) {
            builder.logLevel(config.getLoggerLevel());
        }

        if (config.getConnectTimeout() != null && config.getReadTimeout() != null) {
            builder.options(new Request.Options(config.getConnectTimeout(),
                    config.getReadTimeout()));
        }

        if (config.getRetryer() != null) {
            Retryer retryer = getOrInstantiate(config.getRetryer());
            builder.retryer(retryer);
        }

        if (config.getErrorDecoder() != null) {
            ErrorDecoder errorDecoder = getOrInstantiate(config.getErrorDecoder());
            builder.errorDecoder(errorDecoder);
        }

        if (config.getRequestInterceptors() != null
                && !config.getRequestInterceptors().isEmpty()) {
            // this will add request interceptor to builder, not replace existing
            for (Class<RequestInterceptor> bean : config.getRequestInterceptors()) {
                RequestInterceptor interceptor = getOrInstantiate(bean);
                builder.requestInterceptor(interceptor);
            }
        }

        if (config.getDecode404() != null) {
            if (config.getDecode404()) {
                builder.decode404();
            }
        }

        if (Objects.nonNull(config.getEncoder())) {
            builder.encoder(getOrInstantiate(config.getEncoder()));
        }

        if (Objects.nonNull(config.getDecoder())) {
            builder.decoder(getOrInstantiate(config.getDecoder()));
        }

        if (Objects.nonNull(config.getContract())) {
            builder.contract(getOrInstantiate(config.getContract()));
        }
    }
}

以上过程大致做了以下几件事
1)从this.contextId指定的ApplicationContext中获取类型为feign.Feign.Builder的实例对象(feign.Feign.Builder是个静态内部类),并为Builder对象设置Retryer、ErrorDecoder、RequestInterceptors等
2)从this.contextId指定名称的ApplicationContext中获取类型为feign.Client的实例对象,并设置给Builder【这是与Ribbon集成的关键点】
3)从this.contextId指定名称的ApplicationContext中获取类型为org.springframework.cloud.openfeign.Targeter的实例对象,并设置给Builder【关键点】
4)调用Targeter的target方法,并将结果返回【就是依赖注入的实例】
5)Targeter的target方法内部会调用feign.Feign.Builder的target方法并返回
6)在feign.Feign.Builder内部使用java动态代理创建接口实例Bean

常见的Targeter对象有下面两个
1,org.springframework.cloud.openfeign.DefaultTargeter

class DefaultTargeter implements Targeter {

    @Override
    public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
            FeignContext context, Target.HardCodedTarget<T> target) {
        return feign.target(target);
    }
}

2,org.springframework.cloud.openfeign.HystrixTargeter

class HystrixTargeter implements Targeter {

    @Override
    public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
            FeignContext context, Target.HardCodedTarget<T> target) {
        if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
            return feign.target(target);
        }
        feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
        String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName()
                : factory.getContextId();
        SetterFactory setterFactory = getOptional(name, context, SetterFactory.class);
        if (setterFactory != null) {
            builder.setterFactory(setterFactory);
        }
        Class<?> fallback = factory.getFallback();
        if (fallback != void.class) {
            return targetWithFallback(name, context, target, builder, fallback);
        }
        Class<?> fallbackFactory = factory.getFallbackFactory();
        if (fallbackFactory != void.class) {
            return targetWithFallbackFactory(name, context, target, builder,
                    fallbackFactory);
        }

        return feign.target(target);
    }

    private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,
            Target.HardCodedTarget<T> target, HystrixFeign.Builder builder,
            Class<?> fallbackFactoryClass) {
        FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) getFromContext(
                "fallbackFactory", feignClientName, context, fallbackFactoryClass,
                FallbackFactory.class);
        return builder.target(target, fallbackFactory);
    }

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

    private <T> T getFromContext(String fallbackMechanism, String feignClientName,
            FeignContext context, Class<?> beanType, Class<T> targetType) {
        Object fallbackInstance = context.getInstance(feignClientName, beanType);
        if (fallbackInstance == null) {
            throw new IllegalStateException(String.format(
                    "No " + fallbackMechanism
                            + " instance of type %s found for feign client %s",
                    beanType, feignClientName));
        }

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

    private <T> T getOptional(String feignClientName, FeignContext context,
            Class<T> beanType) {
        return context.getInstance(feignClientName, beanType);
    }
}

Feign.Builder类的源码

public static class Builder {
    //拦截器
    private final List<RequestInterceptor> requestInterceptors =
        new ArrayList<RequestInterceptor>();
    private Logger.Level logLevel = Logger.Level.NONE;
    private Contract contract = new Contract.Default();
    private Client client = new Client.Default(null, null);
    private Retryer retryer = new Retryer.Default();
    private Logger logger = new NoOpLogger();
    private Encoder encoder = new Encoder.Default();
    private Decoder decoder = new Decoder.Default();
    private QueryMapEncoder queryMapEncoder = new QueryMapEncoder.Default();
    private ErrorDecoder errorDecoder = new ErrorDecoder.Default();
    private Options options = new Options();
    private InvocationHandlerFactory invocationHandlerFactory =
        new InvocationHandlerFactory.Default();
    private boolean decode404;
    private boolean closeAfterDecode = true;
    private ExceptionPropagationPolicy propagationPolicy = NONE;

    public Builder logLevel(Logger.Level logLevel) {
      this.logLevel = logLevel;
      return this;
    }
    public Builder contract(Contract contract) {
      this.contract = contract;
      return this;
    }
    public Builder client(Client client) {
      this.client = client;
      return this;
    }
    public Builder retryer(Retryer retryer) {
      this.retryer = retryer;
      return this;
    }
    public Builder logger(Logger logger) {
      this.logger = logger;
      return this;
    }
    public Builder encoder(Encoder encoder) {
      this.encoder = encoder;
      return this;
    }
    public Builder decoder(Decoder decoder) {
      this.decoder = decoder;
      return this;
    }
    public Builder queryMapEncoder(QueryMapEncoder queryMapEncoder) {
      this.queryMapEncoder = queryMapEncoder;
      return this;
    }
    public Builder mapAndDecode(ResponseMapper mapper, Decoder decoder) {
      this.decoder = new ResponseMappingDecoder(mapper, decoder);
      return this;
    }
    public Builder decode404() {
      this.decode404 = true;
      return this;
    }
    public Builder errorDecoder(ErrorDecoder errorDecoder) {
      this.errorDecoder = errorDecoder;
      return this;
    }
    public Builder options(Options options) {
      this.options = options;
      return this;
    }
    public Builder requestInterceptor(RequestInterceptor requestInterceptor) {
      this.requestInterceptors.add(requestInterceptor);
      return this;
    }
    public Builder requestInterceptors(Iterable<RequestInterceptor> requestInterceptors) {
      this.requestInterceptors.clear();
      for (RequestInterceptor requestInterceptor : requestInterceptors) {
        this.requestInterceptors.add(requestInterceptor);
      }
      return this;
    }
    public Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) {
      this.invocationHandlerFactory = invocationHandlerFactory;
      return this;
    }

    public Builder doNotCloseAfterDecode() {
      this.closeAfterDecode = false;
      return this;
    }
    public Builder exceptionPropagationPolicy(ExceptionPropagationPolicy propagationPolicy) {
      this.propagationPolicy = propagationPolicy;
      return this;
    }
    public <T> T target(Class<T> apiType, String url) {
      return target(new HardCodedTarget<T>(apiType, url));
    }
    //被上面调用
    public <T> T target(Target<T> 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);
      //最后会构建一个ReflectiveFeign类型的对象,内部通过动态代理来处理
      return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
    }
  }

到此,其Feign实现的基本流程已经解析完成,主要就是扫描得到各个由@FeignClient注解标注的客户端,然后为每个客户端创建一个FeignClientFactoryBean工厂Bean对象,通过在该工厂Bean内部为Feign客户端创建动态代理对象来实现与Ribbon以及Hystrix的集成。

在后面的章节中将继续解析Feign的自动装配过程,即上面代码中FeignContext、Feign.Builder、Client 、Targeter 等对象的创建过程。

相关文章

网友评论

      本文标题:SpringCloud解析六:Feign解析上

      本文链接:https://www.haomeiwen.com/subject/vilonctx.html