work hard work smart

专注于Java后端开发。 不断总结,举一反三。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

最好的Http客户端--Feign 源码分析

Posted on 2020-03-24 11:28  work hard work smart  阅读(343)  评论(0编辑  收藏  举报

前面介绍了Feign的使用(Feign的使用),

Feign整合Hystrix(Feign整合Hystrix) ,

Feign整合(Feign整合Ribbon负载均衡),

Feign的性能优化(Feign性能优化),

现在介绍下Feign的源码。

通过前面的使用过程,@EnableFeignClients和@FeignClient实现了Feign的功能

一、@EnableFeignClients

1、@EnableFeignClients注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({FeignClientsRegistrar.class})
public @interface EnableFeignClients {
    String[] value() default {};

    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<?>[] defaultConfiguration() default {};

    Class<?>[] clients() default {};
}

  重点是@Import({FeignClientsRegistrar.class})

 

2、FeignClientsRigistar实现了ImportBeanDefinitionRegistrar接口

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
		ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware{
        
	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
                // 1.针对那些在@EnableFeignClients中添加了defaultConfiguration属性的进行操作
                // 将这些类定义的bean添加到容器中
		registerDefaultConfiguration(metadata, registry);
        
              // 2.注册那些添加了@FeignClient的类或接口
		registerFeignClients(metadata, registry);
	}

    

  

3、registerFeignClients(metadata, registry);方法

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

       scanner.setResourceLoader(this.resourceLoader);
        Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
        //@FeignClient注解过滤器
    AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
        Class<?>[] clients = attrs == null ? null : (Class[])((Class[])attrs.get("clients"));
        //1、扫描包下所有带有@FeignClient注解的类
    Object basePackages;
        if (clients != null && clients.length != 0) {
            final Set<String> clientClasses = new HashSet();
            basePackages = new HashSet();
            Class[] var9 = clients;
            int var10 = clients.length;

            for(int var11 = 0; var11 < var10; ++var11) {
                Class<?> clazz = var9[var11];
                ((Set)basePackages).add(ClassUtils.getPackageName(clazz));
                clientClasses.add(clazz.getCanonicalName());
            }

            AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
                protected boolean match(ClassMetadata metadata) {
                    String cleaned = metadata.getClassName().replaceAll("\\$", ".");
                    return clientClasses.contains(cleaned);
                }
            };
            scanner.addIncludeFilter(new FeignClientsRegistrar.AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
        } else {
            scanner.addIncludeFilter(annotationTypeFilter);
            basePackages = this.getBasePackages(metadata);
        }

    //2、针对所有带有@FeignClient注解的类或接口分别封装
    //并将类或接口注入到Spring中
        Iterator var17 = ((Set)basePackages).iterator();
        while(var17.hasNext()) {
            String basePackage = (String)var17.next();
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
            Iterator var21 = candidateComponents.iterator();

            while(var21.hasNext()) {
                BeanDefinition candidateComponent = (BeanDefinition)var21.next();
          //验证被注解的类是否是接口
                if (candidateComponent instanceof AnnotatedBeanDefinition) {
                    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 = this.getClientName(attributes);
            //2.1 注册其Configuration类(如果有的话)
                    this.registerClientConfiguration(registry, name, attributes.get("configuration"));
                    //2.2将类或接口注入到Spring中
            this.registerFeignClient(registry, annotationMetadata, attributes);
                }
            }
        }

    }

  从这里可知,@EnableFeignCliengs注解的主要功能就是把带有@FeignClient注解的类或接口注册到Spring容器中

  

 4、registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes)方法分析

private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
      //1、获取类名称,这里为com.example.springclouddeep.consumer.feign.ProviderApi
       String className = annotationMetadata.getClassName();
      //2、BeanDefinitionBuilder 的作用是构建一个BeanDefinition。BeanDefinition的类为FeignClientFactoryBean
       BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
       this.validate(attributes);
      //添加FeignClientFactoryBean的属性,这些属性都是我们在@FeignClient中定义的属性
       definition.addPropertyValue("url", this.getUrl(attributes));
       definition.addPropertyValue("path", this.getPath(attributes));
       String name = this.getName(attributes);
       definition.addPropertyValue("name", name);
       String contextId = this.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(2);
      //设置别名 name就是我们在@FeignClient中定义的name属性。 这里alias值为hello-service-providerFeignClient
       String alias = contextId + "FeignClient";
       AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
       boolean primary = (Boolean)attributes.get("primary");
       beanDefinition.setPrimary(primary);
       String qualifier = this.getQualifier(attributes);
       if (StringUtils.hasText(qualifier)) {
           alias = qualifier;
       }
 
     //5、定义BeanDefinitionHolder,这里beanDefinition中的beanClass为           //org.springframework.cloud.openfeign.FeignClientFactoryBean<br>        
     //className为com.example.springclouddeep.consumer.feign.ProviderApi,类为FeignClientFactoryBean
       BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[]{alias});
       BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
   }

       通过分析可知:我们最终是向Spring中注册了一个bean,bean的名称就是类或接口的名称(这里com.example.springclouddeep.consumer.feign.ProviderApi,.ProviderApi代码参考Feign整合Hystrix),bean的实现类是FeignClientFactoryBean,其属性设置就是我们在@FeignClient中定义的属性。那FeignClientFactoryBean有什么作用呢?我们下面再来分析

 

总结: 

1)@EnableFeignClients注解类将FeignClientsRegistrar注册到Spring中

2)FeignClientsRegistrar类的主要作用是扫码包路径下的所有类,将带有@FeignClient注解的类或接口注册到Spring中

3)如何注册带有@FeignClient的类或接口呢? 就是生成一个BeanDefinitionHolder类,beanName为@FeignClient所在接口名称,beanDefinition为FeignClientFactoryBean,并将@FeignClient的属性添加到FeignClientFactoryBean中。

 

二、FeignClientFactoryBean

 FeignClientFactoryBean实现了FactoryBean接口,当从ApplicationContext中获取该bean的时候,实际上调用的是getObject()方法

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

    <T> T getTarget() {
	//1、获取容器中的FeignContext实现,默认实现在FeignAutoConfiguration类中
        FeignContext context = (FeignContext)this.applicationContext.getBean(FeignContext.class);
	//2、使用构造器模式来构建一个Feign,后面详细介绍
        Builder builder = this.feign(context);
	//3、判断是否有指定URL
        if (!StringUtils.hasText(this.url)) {
            if (!this.name.startsWith("http")) {
                this.url = "http://" + this.name;
            } else {
                this.url = this.name;
            }

            this.url = this.url + this.cleanPath();
	    //关键方法,后面详细介绍	
            return this.loadBalance(builder, context, new HardCodedTarget(this.type, this.name, this.url));
        } else {
            if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
                this.url = "http://" + this.url;
            }

            String url = this.url + this.cleanPath();
            Client client = (Client)this.getOptional(context, Client.class);
            if (client != null) {
                if (client instanceof LoadBalancerFeignClient) {
                    client = ((LoadBalancerFeignClient)client).getDelegate();
                }

                if (client instanceof FeignBlockingLoadBalancerClient) {
                    client = ((FeignBlockingLoadBalancerClient)client).getDelegate();
                }

                builder.client(client);
            }

            Targeter targeter = (Targeter)this.get(context, Targeter.class);
            return targeter.target(this, builder, context, new HardCodedTarget(this.type, this.name, url));
        }
    }

  

1、构建Builder

 protected Builder feign(FeignContext context) {
        FeignLoggerFactory loggerFactory = (FeignLoggerFactory)this.get(context, FeignLoggerFactory.class);
        Logger logger = loggerFactory.create(this.type);
        Builder builder = ((Builder)this.get(context, Builder.class)).logger(logger).encoder((Encoder)this.get(context, Encoder.class)).decoder((Decoder)this.get(context, Decoder.class)).contract((Contract)this.get(context, Contract.class));
        this.configureFeign(context, builder);
        return builder;
    }


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

    }



    protected void configureUsingConfiguration(FeignContext context, Builder builder) {
	//下面的几项getOptional()主要功能就是从ApplicationContext中获取对应类的实现
	//这些类可以自定义,默认从FeignAutoConfiguration中获取对应的bean
        Level level = (Level)this.getOptional(context, Level.class);
        if (level != null) {
            builder.logLevel(level);
        }

        Retryer retryer = (Retryer)this.getOptional(context, Retryer.class);
        if (retryer != null) {
            builder.retryer(retryer);
        }

        ErrorDecoder errorDecoder = (ErrorDecoder)this.getOptional(context, ErrorDecoder.class);
        if (errorDecoder != null) {
            builder.errorDecoder(errorDecoder);
        }

        Options options = (Options)this.getOptional(context, 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 = (QueryMapEncoder)this.getOptional(context, QueryMapEncoder.class);
        if (queryMapEncoder != null) {
            builder.queryMapEncoder(queryMapEncoder);
        }

        if (this.decode404) {
            builder.decode404();
        }

        ExceptionPropagationPolicy exceptionPropagationPolicy = (ExceptionPropagationPolicy)this.getOptional(context, ExceptionPropagationPolicy.class);
        if (exceptionPropagationPolicy != null) {
            builder.exceptionPropagationPolicy(exceptionPropagationPolicy);
        }

    }

 

2、获取负载均衡后的方法 protected <T> T loadBalance(Builder builder, FeignContext context, HardCodedTarget<T> target) 

protected <T> T loadBalance(Builder builder, FeignContext context, HardCodedTarget<T> target) {
        //1、获取Client的实现类,默认为LoadBalancerFeignClient类
	//实现在FeignRibbonClientAutoConfiguration中
	Client client = (Client)this.getOptional(context, Client.class);
        if (client != null) {
	    //2、将LoadBalancerFeignClient包装到Feign.Builder
            builder.client(client);
	    //3、获取ApplicationContext中的Target实现
	    //默认实现为HystrixTargeter,实现在FeignAutoConfiguration类中
            Targeter targeter = (Targeter)this.get(context, Targeter.class);
	    //4、重点是这里
            return targeter.target(this, builder, context, target);
        } else {
            throw new IllegalStateException("No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
        }
    }


//HystrixTargeter.target
    public <T> T target(FeignClientFactoryBean factory, Builder feign, FeignContext context, HardCodedTarget<T> target) {
	//feign不是feign.hystrix.HystrixFeign.Builder,直接返回return feign.target(target)
        if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
            return feign.target(target);
        } else {
            feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder)feign;
            String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName() : factory.getContextId();
            SetterFactory setterFactory = (SetterFactory)this.getOptional(name, context, SetterFactory.class);
            if (setterFactory != null) {
                builder.setterFactory(setterFactory);
            }

            Class<?> fallback = factory.getFallback();
            if (fallback != Void.TYPE) {
                return this.targetWithFallback(name, context, target, builder, fallback);
            } else {
                Class<?> fallbackFactory = factory.getFallbackFactory();
                return fallbackFactory != Void.TYPE ? this.targetWithFallbackFactory(name, context, target, builder, fallbackFactory) : feign.target(target);
            }
        }
    }

//feign.Feign.Builder.target(target)
public <T> T target(Target<T> target) {
     return this.build().newInstance(target);
 }

 
//feign.Feign.Builder.build()
public Feign build() {
            Factory synchronousMethodHandlerFactory = new Factory(this.client, this.retryer, this.requestInterceptors, this.logger, this.logLevel, this.decode404, this.closeAfterDecode, this.propagationPolicy);
            ParseHandlersByName handlersByName = new ParseHandlersByName(this.contract, this.options, this.encoder, this.decoder, this.queryMapEncoder, this.errorDecoder, synchronousMethodHandlerFactory);
           //这里看到了ReflectiveFeign
	   return new ReflectiveFeign(handlersByName, this.invocationHandlerFactory, this.queryMapEncoder);
        }

//ReflectiveFeign.newInstance(target)
 public <T> T newInstance(Target<T> target) {
	//1、分析出具体方法和对应的Handler处理
        Map<String, MethodHandler> nameToHandler = this.targetToHandlersByName.apply(target);
        Map<Method, MethodHandler> methodToHandler = new LinkedHashMap();
        List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList();
        Method[] var5 = target.type().getMethods();
        int var6 = var5.length;

        for(int var7 = 0; var7 < var6; ++var7) {
            Method method = var5[var7];
            if (method.getDeclaringClass() != Object.class) {
                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)));
                }
            }
        }

	//2、由factory创建一个InvocationHandler,实现为FeignInvocationHandler
	//target为HardCodedTarget
        InvocationHandler handler = this.factory.create(target, methodToHandler);
        //最终返回的是一个代理
	 T proxy = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, handler);
        Iterator var12 = defaultMethodHandlers.iterator();

        while(var12.hasNext()) {
            DefaultMethodHandler defaultMethodHandler = (DefaultMethodHandler)var12.next();
            defaultMethodHandler.bindTo(proxy);
        }

        return proxy;
    }

 由以上分析可知,getObject()具体返回的是一个代理类,具体为FeignInvocationHandler 

 

3、FeignInvocationHandler

static class FeignInvocationHandler implements InvocationHandler {
        
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (!"equals".equals(method.getName())) {
                if ("hashCode".equals(method.getName())) {
                    return this.hashCode();
                } else {
		    //非Object方法,则执行this.dispatch.get(method)).invoke(args)
		    //dispath为map,方法的实现类为SynchronousMethodHandle。
		    //我们接下来分析SynchronousMethodHandle.invoke(args)
                    return "toString".equals(method.getName()) ? this.toString() : ((MethodHandler)this.dispatch.get(method)).invoke(args);
                }
            } else {
                try {
                    Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
                    return this.equals(otherHandler);
                } catch (IllegalArgumentException var5) {
                    return false;
                }
            }
        }

        
      
    }

  1)、SynchronousMethodHandle.invoke(args)

 public Object invoke(Object[] argv) throws Throwable {
	//1、根据请求参数创建一个RequestTemplate 
        RequestTemplate template = this.buildTemplateFromArgs.create(argv);
        Options options = this.findOptions(argv);
	//2、用户定义的重试策略
        Retryer retryer = this.retryer.clone();

        while(true) {
            try {
		//下面介绍这个方法
                return this.executeAndDecode(template, options);
            } catch (RetryableException var9) {
                RetryableException e = var9;

                try {
                    retryer.continueOrPropagate(e);
                } catch (RetryableException var8) {
                    Throwable cause = var8.getCause();
                    if (this.propagationPolicy == ExceptionPropagationPolicy.UNWRAP && cause != null) {
                        throw cause;
                    }

                    throw var8;
                }

                if (this.logLevel != Level.NONE) {
                    this.logger.logRetry(this.metadata.configKey(), this.logLevel);
                }
            }
        }
    

  

2)executeAndDecode(template, options)

Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
        //分装请求信息 
	Request request = this.targetRequest(template);
        if (this.logLevel != Level.NONE) {
            this.logger.logRequest(this.metadata.configKey(), this.logLevel, request);
        }

        long start = System.nanoTime();

        Response response;
        try {
	    //执行。 client为LoadBalancerFeignClient,下面介绍exetute方法
            response = this.client.execute(request, options);
            response = response.toBuilder().request(request).requestTemplate(template).build();
        } catch (IOException var16) {
            if (this.logLevel != Level.NONE) {
                this.logger.logIOException(this.metadata.configKey(), this.logLevel, var16, this.elapsedTime(start));
            }

            throw FeignException.errorExecuting(request, var16);
        }
    	//响应处理
        long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
        boolean shouldClose = true;

        Object var11;
        try {
            if (this.logLevel != Level.NONE) {
                response = this.logger.logAndRebufferResponse(this.metadata.configKey(), this.logLevel, response, elapsedTime);
            }

            if (Response.class == this.metadata.returnType()) {
                Response var19;
                if (response.body() == null) {
                    var19 = response;
                    return var19;
                }

                if (response.body().length() != null && (long)response.body().length() <= 8192L) {
                    byte[] bodyData = Util.toByteArray(response.body().asInputStream());
                    Response var21 = response.toBuilder().body(bodyData).build();
                    return var21;
                }

                shouldClose = false;
                var19 = response;
                return var19;
            }

            Object result;
            if (response.status() >= 200 && response.status() < 300) {
                if (Void.TYPE == this.metadata.returnType()) {
                    result = null;
                    return result;
                }

                result = this.decode(response);
                shouldClose = this.closeAfterDecode;
                var11 = result;
                return var11;
            }

            if (!this.decode404 || response.status() != 404 || Void.TYPE == this.metadata.returnType()) {
                throw this.errorDecoder.decode(this.metadata.configKey(), response);
            }

            result = this.decode(response);
            shouldClose = this.closeAfterDecode;
            var11 = result;
        } catch (IOException var17) {
            if (this.logLevel != Level.NONE) {
                this.logger.logIOException(this.metadata.configKey(), this.logLevel, var17, elapsedTime);
            }

            throw FeignException.errorReading(request, response, var17);
        } finally {
            if (shouldClose) {
                Util.ensureClosed(response.body());
            }

        }

        return var11;
    }

  

3) LoadBalancerFeignClient的exetute方法

public Response execute(Request request, Options options) throws IOException {
        try {
	    //1、获得URI
            URI asUri = URI.create(request.url());
            String clientName = asUri.getHost();
            URI uriWithoutHost = cleanUrl(request.url(), clientName);
            //2、封装RibbonRequest请求
	    RibbonRequest ribbonRequest = new RibbonRequest(this.delegate, request, uriWithoutHost);
            //3、封装请求参数信息
	    IClientConfig requestConfig = this.getClientConfig(options, clientName);
            //4、执行请求,并信息负载均衡
	    1)lbClient(clientName)获得执行类。这里为FeignLoadBalancer
	    2)FeignLoadBalancer.executeWithLoadBalancer() 执行请求。 下面介绍
	    3)toResponse()获得响应
	    return ((RibbonResponse)this.lbClient(clientName).executeWithLoadBalancer(ribbonRequest, requestConfig)).toResponse();
        } catch (ClientException var8) {
            IOException io = this.findIOException(var8);
            if (io != null) {
                throw io;
            } else {
                throw new RuntimeException(var8);
            }
        }
    }

  

4) FeignLoadBalancer.executeWithLoadBalancer()执行请求

public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
        LoadBalancerCommand command = this.buildLoadBalancerCommand(request, requestConfig);

        try {
	    //这里是Hystrix的相关代码
            return (IResponse)command.submit(new ServerOperation<T>() {
                public Observable<T> call(Server server) {
                    URI finalUri = AbstractLoadBalancerAwareClient.this.reconstructURIWithServer(server, request.getUri());
                    ClientRequest requestForServer = request.replaceUri(finalUri);

                    try {
			//执行ribbon负载均衡器
                        return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
                    } catch (Exception var5) {
                        return Observable.error(var5);
                    }
                }
            }).toBlocking().single();
        } catch (Exception var6) {
            Throwable t = var6.getCause();
            if (t instanceof ClientException) {
                throw (ClientException)t;
            } else {
                throw new ClientException(var6);
            }
        }
    }

  总结:

  1、FeignClientFactoryBean.getObject()方法返回的是一个代理类,InvocationHandler中包含类中每个方法对应的MethodHandler,也就是SynchronousMethodHandler,方法真正执行就是SynchronousMethodHandler.invoke()方法

  2.LoadBalancerFeignClient.execute()方法进行业务的处理,在这一步操作中就用到了ribbon和Hystrix功能