Feign源码解析

在使用Feign接口的时候我们首先要添加@EnableFeignClient注解,注解@EnableFeignClient导入了类FeignClientsRegistrar,如下:

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(FeignClientsRegistrar.class) public @interface EnableFeignClients {}

类FeignClientsRegistrar实现了ImportBeanDefinitionRegistrar接口,所以在Spring实例化的过程中会回调registerBeanDefinitions()方法,此方法会注册相关的BeanDefinition,基本上所有的注解都是这样的一个套路。从源码可以看到registerBeanDefinitions()先是从basePackages中扫描标记了@FeignClient的接口,如下:
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { // 省略for (String basePackage : basePackages) { Set candidateComponents = scanner .findCandidateComponents(basePackage); for (BeanDefinition candidateComponent : candidateComponents) { if (candidateComponent instanceof AnnotatedBeanDefinition) { // verify annotated class is an interface AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent; AnnotationMetadata annotationMetadata = https://www.it610.com/article/beanDefinition.getMetadata(); Assert.isTrue(annotationMetadata.isInterface(),"@FeignClient can only be specified on an interface"); Map attributes = annotationMetadata .getAnnotationAttributes( FeignClient.class.getCanonicalName()); String name = getClientName(attributes); registerClientConfiguration(registry, name, attributes.get("configuration")); registerFeignClient(registry, annotationMetadata, attributes); } } } }

然后针对扫描到的每一个@FeignClient接口调用了registerFeignClient()方法,此方法为Feign接口注册了FeignClientFactoryBean类的BeanDefinition,如下:
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map attributes) { String className = annotationMetadata.getClassName(); BeanDefinitionBuilder definition = BeanDefinitionBuilder .genericBeanDefinition(FeignClientFactoryBean.class); validate(attributes); definition.addPropertyValue("url", getUrl(attributes)); definition.addPropertyValue("path", getPath(attributes)); String name = getName(attributes); definition.addPropertyValue("name", name); 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 nullbeanDefinition.setPrimary(primary); String qualifier = getQualifier(attributes); if (StringUtils.hasText(qualifier)) { alias = qualifier; }BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias }); BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); }

通过查看FeignClientFactoryBean的源码可以发现FeignClientFactoryBean实现了FactoryBean接口,FactoryBean接口是一个可以自定义实例化对象的一个接口,至此,我们已经知道了在实例化Feign接口的时候会调用FeignClientFactoryBean的getObject()方法返回对象实例。所以就重点看下FeignClientFactoryBean的getObject()方法是如何返回一个Feign接口实例的。其相关源码如下:
protected T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget 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); }throw new IllegalStateException( "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?"); }@Override public Object getObject() throws Exception { return getTarget(); }/** * @param the target type of the Feign client * @return a {@link Feign} client created with the specified data and the context information */ T getTarget() { FeignContext context = applicationContext.getBean(FeignContext.class); Feign.Builder builder = feign(context); if (!StringUtils.hasText(this.url)) { if (!this.name.startsWith("http")) { url = "http://" + this.name; } else { url = this.name; } url += cleanPath(); return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type, this.name, url)); } if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) { this.url = "http://" + this.url; } String url = this.url + cleanPath(); 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)); }

可以看到getObject()方法直接调用target()方法,getTarget()方法获取了FeignContext、Feign.Builder、new HardCodedTarget实例,然后调用loadBalance()方法,此方法会从Spring上下文中找Client和Targeter并调用Targeter的target()方法生成代理对象,Targeter的实现类有两个:DefaultTargeter和HystrixTargeter。DefaultTargeter的target()方法直接调用Feign.Builder的target()方法返回对象实例。HystrixTargeter的target()方法会根据Feign接口配置以及Feign.Builder的类型来决定调用DefaultTargeter的target()还是HystrixTargeter的target()返代理对象。在引入Hystrix相关依赖后就会使用HystrixTargeter,如下为HystrixTargeter的target()方法源码:
@Override public T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget target) { 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); }return feign.target(target); }

因为引入了Hystrix相关依赖所以这里的Feign.Builder类型为HystrixFeign.Builder,HystrixFeign.Builder的target()方法创建了匿名InvocationHandlerFactory对象和ReflectiveFeign对象并调用ReflectiveFeign的newInstance()方法返回代理对象,匿名InvocationHandlerFactory对象的create()方法返回了类HystrixInvocationHandler的对象实例,如下为HystrixFeign.Builder类的源码片段:
public T target(Target target, FallbackFactory fallbackFactory) { return build(fallbackFactory).newInstance(target); }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(); }

上面代码中super.build()返回的即为ReflectiveFeign对象,如下:
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); }

ReflectiveFeign的newInstance()方法首先会分析Feign接口中的方法并生成MethodHandler对象,接着调用InvocationHandlerFactory的create()方法创建InvocationHandler并使用JDK的代理方法生成代理对象,如下:
public T newInstance(Target target) { Map nameToHandler = targetToHandlersByName.apply(target); Map methodToHandler = new LinkedHashMap(); List defaultMethodHandlers = new LinkedList(); 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 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; }

此处的InvocationHandler即为上面提到的匿名InvocationHandlerFactory对象的create()方法返回的HystrixInvocationHandler的对象实例,HystrixInvocationHandler为熔断器Hystrix的InvocationHandler实现,其invoke()方法引入了Hystrix的熔断模块。当没有引入Hystrix当相关依赖时InvocationHandlerFactory当实现为默认实现InvocationHandlerFactory.Default,此实现的create()方法返回的InvocationHandler为ReflectiveFeign.FeignInvocationHandler,源码如下:
public interface InvocationHandlerFactory {InvocationHandler create(Target target, Map dispatch); static final class Default implements InvocationHandlerFactory {@Override public InvocationHandler create(Target target, Map dispatch) { return new ReflectiveFeign.FeignInvocationHandler(target, dispatch); } } }

类ReflectiveFeign.FeignInvocationHandler的属性dispatch保存了Method到MethodHandler
的映射,invoke()方法会根据Method找到MethodHandler并执行其invoke()方法,源码如下:
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("equals".equals(method.getName())) { try { Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null; return equals(otherHandler); } catch (IllegalArgumentException e) { return false; } } else if ("hashCode".equals(method.getName())) { return hashCode(); } else if ("toString".equals(method.getName())) { return toString(); }return dispatch.get(method).invoke(args); }

MethodHandler的具体实现为SynchronousMethodHandler,此类的invoke()方法创建RequestTemplate对象并交由Client执行,调用Client的execute()方法发起Http请求并返回Response对象,完成一个请求的调用,如下:
@Override public Object invoke(Object[] argv) throws Throwable { RequestTemplate template = buildTemplateFromArgs.create(argv); Retryer retryer = this.retryer.clone(); while (true) { try { return executeAndDecode(template); } catch (RetryableException e) { try { retryer.continueOrPropagate(e); } catch (RetryableException th) { Throwable cause = th.getCause(); if (propagationPolicy == UNWRAP && cause != null) { throw cause; } else { throw th; } } if (logLevel != Logger.Level.NONE) { logger.logRetry(metadata.configKey(), logLevel); } continue; } } }Object executeAndDecode(RequestTemplate template) throws Throwable { Request request = targetRequest(template); if (logLevel != Logger.Level.NONE) { logger.logRequest(metadata.configKey(), logLevel, request); }Response response; long start = System.nanoTime(); try { response = client.execute(request, options); } catch (IOException e) { if (logLevel != Logger.Level.NONE) { logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start)); } throw errorExecuting(request, e); } // 略 }

Client的实现有两个:Client.Default和LoadBalancerFeignClient,前者使用HttpURLConnection发起Http请求,后者调用FeignLoadBalancer的executeWithLoadBalancer方法使用Ribbon负载均衡发起Http请求。Client.Default源码如下:
package feign; public interface Client { Response execute(Request request, Options options) throws IOException; public static class Default implements Client {// 省略@Override public Response execute(Request request, Options options) throws IOException { HttpURLConnection connection = convertAndSend(request, options); return convertResponse(connection, request); }HttpURLConnection convertAndSend(Request request, Options options) throws IOException { final HttpURLConnection connection = (HttpURLConnection) new URL(request.url()).openConnection(); if (connection instanceof HttpsURLConnection) { HttpsURLConnection sslCon = (HttpsURLConnection) connection; if (sslContextFactory != null) { sslCon.setSSLSocketFactory(sslContextFactory); } if (hostnameVerifier != null) { sslCon.setHostnameVerifier(hostnameVerifier); } } // 略 return connection; }Response convertResponse(HttpURLConnection connection, Request request) throws IOException { int status = connection.getResponseCode(); String reason = connection.getResponseMessage(); // 略 return Response.builder() .status(status) .reason(reason) .headers(headers) .request(request) .body(stream, length) .build(); } } }

LoadBalancerFeignClient类相关源码:
public class LoadBalancerFeignClient implements Client {// 略@Override public Response execute(Request request, Request.Options options) throws IOException { try { URI asUri = URI.create(request.url()); 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); return lbClient(clientName).executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse(); } catch (ClientException e) { IOException io = findIOException(e); if (io != null) { throw io; } throw new RuntimeException(e); } }private FeignLoadBalancer lbClient(String clientName) { return this.lbClientFactory.create(clientName); }// 略 }

总结
Feign接口运行过程大致分为如下几个步骤:
  1. @EnableFeignClient注解导入了FeignClientsRegistrar类。
  2. 执行FeignClientsRegistrar的registerBeanDefinitions()方法扫描basePackages中的Feign接口并为每个Feign接口注册FeignClientFactoryBean的BeanDefinition。
  3. Spring在实例化Feign接口时调用FeignClientFactoryBean类的getObject()方法返回Feign接口的代理实例。
  4. 创建InvocationHandler对象并使用JDK代理生成代理类。
  5. 如果引入了Hystrix的相关依赖则引入Hystrix的熔断模块(HystrixInvocationHandler)。
  6. 如果引入了Ribbon的相关依赖则Client接口会引入Ribbon的负载均衡模块(LoadBalancerFeignClient)。
  7. 发起Http调用,返回结果。
【Feign源码解析】相关类图如下:

Feign源码解析
文章图片
image

    推荐阅读