例子这次先不写了。。。间接源码走起。局部设计跟Ribbon一样,这边就不在累述,倡议先看Ribbon系列。
仍然从spring.factories说起。留神到这里有这几个类:FeignAutoConfiguration、FeignRibbonClientAutoConfiguration。

启动

FeignAutoConfiguration

加载FeignContext,这里会赋值FeignClientSpecification的汇合,
前面说FeignClientSpecification类怎么来的,其实跟Ribbon用的是同一个办法。
FeignContext的defaultConfigType是FeignClientsConfiguration.class,这个和Ribboon用法一样,前面会加载。

@Autowired(required = false)private List<FeignClientSpecification> configurations = new ArrayList<>();@Beanpublic FeignContext feignContext() {    FeignContext context = new FeignContext();    context.setConfigurations(this.configurations);    return context;}

另一个加载的是HystrixTargeter,尽管是HystrixTargeter,如果Feign.Builder不是feign.hystrix.HystrixFeign.Builder,前面调用的还是Feign.Builder的target办法。

@Configuration(proxyBeanMethods = false)@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")protected static class HystrixFeignTargeterConfiguration {    @Bean    @ConditionalOnMissingBean    public Targeter feignTargeter() {        return new HystrixTargeter();    }}

FeignRibbonClientAutoConfiguration

加载CachingSpringLoadBalancerFactory,这个类会注入SpringClientFactory,看过了Ribbon,是不是就晓得了他要做什么。没错,他会创立一个ILoadBalancer,用于负载平衡。

@Bean@Primary@ConditionalOnMissingBean@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")public CachingSpringLoadBalancerFactory cachingLBClientFactory(        SpringClientFactory factory) {    return new CachingSpringLoadBalancerFactory(factory);}

FeignRibbonClientAutoConfiguration还import了DefaultFeignLoadBalancedConfiguration类,在这个类,会创立一个LoadBalancerFeignClient,前面须要的Client就是他了。

@Bean@ConditionalOnMissingBeanpublic Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,        SpringClientFactory clientFactory) {    return new LoadBalancerFeignClient(new Client.Default(null, null), cachingFactory,            clientFactory);}

@EnableFeignClients

咱们应用feign的时候,都会应用这个注解,注解里Import了FeignClientsRegistrar这个类,FeignClientsRegistrar实现了ImportBeanDefinitionRegistrar接口,调用registerBeanDefinitions办法。这个办法做了两件事,一件事是注册FeignClientSpecification类,前面会注入到下面的FeignContext中,这个用法跟Ribbon - 几种自定义负载平衡策略提的一样。另外一件事就是创立FactoryBean。

@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata,        BeanDefinitionRegistry registry) {    // 注册FeignClientSpecification类    registerDefaultConfiguration(metadata, registry);    // 通过注解的信息注册FeignClientFactoryBean类,    //这个是FactoryBean,所以容器fresh的时候会调用他的getObject办法    registerFeignClients(metadata, registry);}

这个办法就会扫描EnableFeignClients和FeignClient的注解,而后注册FeignClientFactoryBean类型的bean,这个是FactoryBean,所以容器fresh的时候会调用他的getObject办法。

public void registerFeignClients(AnnotationMetadata metadata,        BeanDefinitionRegistry registry) {    LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();    // 扫描EnableFeignClients注解    Map<String, Object> attrs = metadata            .getAnnotationAttributes(EnableFeignClients.class.getName());        AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(            FeignClient.class);    final Class<?>[] clients = attrs == null ? null            : (Class<?>[]) attrs.get("clients");    // 如果EnableFeignClients没有配置clients信息,扫描FeignClient注解    if (clients == null || clients.length == 0) {        ClassPathScanningCandidateComponentProvider scanner = getScanner();        scanner.setResourceLoader(this.resourceLoader);        // 扫描FeignClient注解        scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));        Set<String> basePackages = getBasePackages(metadata);        for (String basePackage : basePackages) {            candidateComponents.addAll(scanner.findCandidateComponents(basePackage));        }    }    else {        // 如果配置clients信息,就疏忽FeignClient注解,间接读取clients信息        for (Class<?> clazz : clients) {            candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));        }    }    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);            registerClientConfiguration(registry, name,                    attributes.get("configuration"));            // 注册FeignClientFactoryBean            registerFeignClient(registry, annotationMetadata, attributes);        }    }}

FeignClientFactoryBean#getObject

getObject会调用getTarget办法,他会创立一个Feign.Builder,创立的时候会传FeignContext,这个FeignContext的加载在下面曾经提过了。而后调用loadBalance办法返回代理对象,这个代理就是前面近程调用用的。

<T> T getTarget() {    FeignContext context = applicationContext.getBean(FeignContext.class);    Feign.Builder builder = feign(context);    if (!StringUtils.hasText(url)) {        if (!name.startsWith("http")) {            url = "http://" + name;        }        else {            url = name;        }        url += cleanPath();        return (T) loadBalance(builder, context,                new HardCodedTarget<>(type, name, url));    }    // 间接ip的模式,代码略}

FeignClientFactoryBean#feign

创立一个Feign.Builder,FeignContext#getInstance,这个类继承了NamedContextFactory,流程和ribbon的SpringClientFactory#getContext一样。下面提到FeignContext的defaultConfigType是FeignClientsConfiguration.class,所以还会加载OptionalDecoder解码、SpringEncoder编码、SpringMvcContract,解析MVC注解、NEVER_RETRY重试、DefaultFeignLoggerFactory日志、FeignClientConfigurer、Feign.builder()。

protected Feign.Builder feign(FeignContext context) {    FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);    Logger logger = loggerFactory.create(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    // 整合配置Feign.Builder    configureFeign(context, builder);    return builder;}

FeignClientFactoryBean#loadBalance

这里获取Client和Targeter类,Client就是下面的LoadBalancerFeignClient,他是所有共享的。Targeter是HystrixTargeter,他是serviceId公有的。下面曾经提了他最终是调用Feign.Builder#target。

protected <T> T loadBalance(Feign.Builder builder, FeignContext context,        HardCodedTarget<T> target) {    Client client = getOptional(context, Client.class);    if (client != null) {        builder.client(client);        Targeter targeter = get(context, Targeter.class);        return targeter.target(this, builder, context, target);    }    // 异样略}

Feign.Builder#target

build办法是构建一个ReflectiveFeign对象,newInstance是生成代理对象。

public <T> T target(Target<T> target) {  return build().newInstance(target);}

build办法中,ReflectiveFeign创立的时候传了ParseHandlersByName,InvocationHandlerFactory,SynchronousMethodHandler三个对象。

public Feign build() {  // 其余略  return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);}

代理对象生成,生成后,前面对代理对象的拜访,都会调用FeignInvocationHandler#invoke办法。

public <T> T newInstance(Target<T> target) {    // ParseHandlersByName是通过Contrac用来解析接口定义。    Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);    // 给每个办法创立一个SynchronousMethodHandler对象    Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();    List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();    for (Method method : target.type().getMethods()) {      if (method.getDeclaringClass() == Object.class) {        continue;      } else if (Util.isDefault(method)) {        DefaultMethodHandler handler = new DefaultMethodHandler(method);        defaultMethodHandlers.add(handler);        methodToHandler.put(method, handler);      } else {        methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));      }    }    // 创立一个InvocationHandler对象,这里是FeignInvocationHandler    InvocationHandler handler = factory.create(target, methodToHandler);    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),        new Class<?>[] {target.type()}, handler);    for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {      defaultMethodHandler.bindTo(proxy);    }    return proxy;}

总结

启动的时候,为每个接口,生成代理对象。

办法调用

FeignInvocationHandler#invoke

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    // 其余略    //dispatch.get(method)获取的是SynchronousMethodHandler    return dispatch.get(method).invoke(args);}

SynchronousMethodHandler#invoke

调用LoadBalancerFeignClient#execute,LoadBalancerFeignClient加载下面曾经讲过了。

public Object invoke(Object[] argv) throws Throwable {    RequestTemplate template = buildTemplateFromArgs.create(argv);    // 其余略    return executeAndDecode(template, options);   // 其余略}Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {    // 其余略    response = client.execute(request, options);    // 其余略}

LoadBalancerFeignClient#execute

@Overridepublic Response execute(Request request, Request.Options options) throws IOException {    try {        // 获取Uri        URI asUri = URI.create(request.url());        // 获取serviceId        String clientName = asUri.getHost();        URI uriWithoutHost = cleanUrl(request.url(), clientName);        FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(                this.delegate, request, uriWithoutHost);                IClientConfig requestConfig = getClientConfig(options, clientName);        // 获取FeignLoadBalancer,通过FeignLoadBalancer调用申请        return lbClient(clientName)                .executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();    }    catch (ClientException e) {        IOException io = findIOException(e);        if (io != null) {            throw io;        }        throw new RuntimeException(e);    }}

lbClientFactory是CachingSpringLoadBalancerFactory,所以调用CachingSpringLoadBalancerFactory#create的create办法。
CachingSpringLoadBalancerFactory有个相熟的SpringClientFactory对象,他负责获取ILoadBalancer、IClientConfig、ServerIntrospector,而后通过这三个构建一个FeignLoadBalancer对象。既然失去了ILoadBalancer,那后续负载平衡的局部就不再持续了,参考Ribbon - 负载平衡流程。

private FeignLoadBalancer lbClient(String clientName) {    return this.lbClientFactory.create(clientName);}public FeignLoadBalancer create(String clientName) {    FeignLoadBalancer client = this.cache.get(clientName);    if (client != null) {        return client;    }    IClientConfig config = this.factory.getClientConfig(clientName);    ILoadBalancer lb = this.factory.getLoadBalancer(clientName);    ServerIntrospector serverIntrospector = this.factory.getInstance(clientName,            ServerIntrospector.class);    client = this.loadBalancedRetryFactory != null            ? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,                    this.loadBalancedRetryFactory)            : new FeignLoadBalancer(lb, config, serverIntrospector);    this.cache.put(clientName, client);    return client;}

总结

次要是通过代理对象,而后调用Ribbon进行负载平衡。咱们这边只讲述了主流程,怎么构建HTTP申请,怎么解决返回后果,都略过了。。。。。