Skip to content

Latest commit

History

History
689 lines (575 loc) · 29.7 KB

File metadata and controls

689 lines (575 loc) · 29.7 KB

OpenFeign

前置

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<!--<version>3.0.6</version>-->
</dependency>

Starters可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包。所以它大概率会和SpringBoot自动装配有联系,找一下spring.factories文件。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.openfeign.hateoas.FeignHalAutoConfiguration,\
org.springframework.cloud.openfeign.FeignAutoConfiguration,\
org.springframework.cloud.openfeign.encoding.FeignAcceptGzipEncodingAutoConfiguration,\
org.springframework.cloud.openfeign.encoding.FeignContentGzipEncodingAutoConfiguration,\
org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoConfiguration

再进行源码分析前,需要带着以下几个问题,有目的的源码学习:

  1. @FeignClient注入的接口,如何被解析和注入的呢?

  2. @Autowired可以针对@FeignClient注入实例对象,是如何注入的,注入的又是什么对象呢?

  3. FeignClient声明的接口被解析后,以什么方式存储和调用的呢?

  4. OpenFeign如何实现负载均衡的呢?

  5. OpenFeign如何发现服务?

OpenFeign源码解析

FeignClient注入初始化

OpenFeign要生效需要使用@EnableFeignClients

packageorg.springframework.cloud.openfeign;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
// ...
}

可以看到@EnableFeignClients注解向容器种导入了一个类FeignClientsRegistrar,从类名上看也能知道其功能是 FeignClient 客户端类的注册。

classFeignClientsRegistrarimplementsImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
@OverridepublicvoidregisterBeanDefinitions(AnnotationMetadatametadata, BeanDefinitionRegistryregistry) {
// 获取 @EnableFeignClients 注解参数 defaultConfiguration,完成一些配置内容注册registerDefaultConfiguration(metadata, registry);
// 重点,注册FeignClient客户端registerFeignClients(metadata, registry);
}
}

关注点在registerFeignClients()方法

classFeignClientsRegistrarimplementsImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
publicvoidregisterFeignClients(AnnotationMetadatametadata, BeanDefinitionRegistryregistry) {
LinkedHashSet<BeanDefinition> candidateComponents = newLinkedHashSet<>();
// 收集该注解的元数据信息:value ,basePackages ,basePackageClasses 等Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
// 获取 @EnableFeignClients 注解中的 client 属性finalClass<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");
// 如果没有配置client相关属性会进入到这里if (clients == null || clients.length == 0) {
ClassPathScanningCandidateComponentProviderscanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
// 添加需要扫描的注解 @FeignClientscanner.addIncludeFilter(newAnnotationTypeFilter(FeignClient.class));
// 根据 @EnableFeignClients 注解的属性信息去获取需要扫描的路径Set<String> basePackages = getBasePackages(metadata);
for (StringbasePackage : basePackages) {
// 找到候选的对象(标有 @FeignClient 注解的接口)封装成BeanDefinition对象// 然后将候选接口添加到 candidateComponents 集合中candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
}
}
else {
// 如果clients属性有值,则直接把指定的clients加入候选者for (Class<?> clazz : clients) {
candidateComponents.add(newAnnotatedGenericBeanDefinition(clazz));
}
}
// 遍历所有的接口,封装BeanDefinition,然后注册到Spring IOC容器.for (BeanDefinitioncandidateComponent : candidateComponents) {
// 断是否是带有注解的 Beanif (candidateComponentinstanceofAnnotatedBeanDefinition) {
// 判断是否是接口AnnotatedBeanDefinitionbeanDefinition = (AnnotatedBeanDefinition) candidateComponent;
AnnotationMetadataannotationMetadata = beanDefinition.getMetadata();
// @FeignClient 只能指定在接口上Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");
// 获取每个接口中定义的元数据信息,即 @FeignClient 注解中配置的属性值,例如:value,name,path,url等Map<String, Object> attributes = annotationMetadata
.getAnnotationAttributes(FeignClient.class.getCanonicalName());
// 获取name的属性值(服务名)Stringname = getClientName(attributes);
// 注册该FeignClient的配置类,FeignClient注解上的configuration属性,其实是注册一个FeignClientSpecification// 该属性值将会作为构造器参数传入,每个FeignClient都有自己的spring上下文registerClientConfiguration(registry, name, attributes.get("configuration"));
// 注册 FeignClient,其实就是注册一个FactoryBeanregisterFeignClient(registry, annotationMetadata, attributes);
}
}
}
protectedSet<String> getBasePackages(AnnotationMetadataimportingClassMetadata) {
// @EnableFeignClients 元数据信息Map<String, Object> attributes = importingClassMetadata
.getAnnotationAttributes(EnableFeignClients.class.getCanonicalName());
Set<String> basePackages = newHashSet<>();
// 遍历属性信息,拿到需要扫描的路径for (Stringpkg : (String[]) attributes.get("value")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
for (Stringpkg : (String[]) attributes.get("basePackages")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
for (Class<?> clazz : (Class[]) attributes.get("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(importingClassMetadata.getClassName()));
}
returnbasePackages;
}
}

registerFeignClients()方法的主要步骤如下:

  1. 查找FeignClient。

  2. 得到一个 @FeignClient 的接口的集合。

  3. 解析 @FeignClient 注解中的元数据信息。

  4. 遍历FeignClient接口,注入一个动态Bean实例(通过动态代理的方式实现)

registerFeignClient(),其内部就是生成接口对应的代理类并诸如到容器中,是一个FeignClientFactoryBean。

classFeignClientsRegistrarimplementsImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
privatevoidregisterFeignClient(BeanDefinitionRegistryregistry, AnnotationMetadataannotationMetadata,
Map<String, Object> attributes) {
// 获取到标注了 @FeignClient 注解的接口全路径,eg: com.train.service.feign.BaseInfoManagementFeignStringclassName = annotationMetadata.getClassName();
Classclazz = ClassUtils.resolveClassName(className, null);
ConfigurableBeanFactorybeanFactory = registryinstanceofConfigurableBeanFactory
? (ConfigurableBeanFactory) registry : null;
StringcontextId = getContextId(beanFactory, attributes);
Stringname = getName(attributes);
// 创建FeignClientFactoryBeanFeignClientFactoryBeanfactoryBean = newFeignClientFactoryBean();
factoryBean.setBeanFactory(beanFactory);
// 将属性设置到 FeignClientFactoryBean 中,也就是在@FeignClient中配置的属性值factoryBean.setName(name);
factoryBean.setContextId(contextId);
factoryBean.setType(clazz);
factoryBean.setRefreshableClient(isClientRefreshEnabled());
/* 设置 bean 的 instanceSupplier,指定spring bean实例化策略为 supplier 方式 BeanDefinitionBuilder 用来构建一个 BeanDefinition 它是通过 genericBeanDefinition 来构建的,并且传入了一个 FeignClientFactoryBean 的类 */BeanDefinitionBuilderdefinition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> {
factoryBean.setUrl(getUrl(beanFactory, attributes));
factoryBean.setPath(getPath(beanFactory, attributes));
factoryBean.setDecode404(Boolean.parseBoolean(String.valueOf(attributes.get("decode404"))));
Objectfallback = attributes.get("fallback");
if (fallback != null) {
factoryBean.setFallback(fallbackinstanceofClass ? (Class<?>) fallback
: ClassUtils.resolveClassName(fallback.toString(), null));
}
ObjectfallbackFactory = attributes.get("fallbackFactory");
if (fallbackFactory != null) {
factoryBean.setFallbackFactory(fallbackFactoryinstanceofClass ? (Class<?>) fallbackFactory
: ClassUtils.resolveClassName(fallbackFactory.toString(), null));
}
returnfactoryBean.getObject();
});
// 指定按类型注入definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
// 懒加载definition.setLazyInit(true);
// 属性值校验validate(attributes);
AbstractBeanDefinitionbeanDefinition = definition.getBeanDefinition();
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
beanDefinition.setAttribute("feignClientsRegistrarFactoryBean", factoryBean);
// has a default, won't be nullbooleanprimary = (Boolean) attributes.get("primary");
// 指定为首选 BeanbeanDefinition.setPrimary(primary);
String[] qualifiers = getQualifiers(attributes);
if (ObjectUtils.isEmpty(qualifiers)) {
qualifiers = newString[] { contextId + "FeignClient" };
}
// 将BeanDefinition包装成BeanDefinitionHolder,用于注册BeanDefinitionHolderholder = newBeanDefinitionHolder(beanDefinition, className, qualifiers);
// 注册 BeanDefinitionBeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
// 注册可选的Request.Options,可以动态刷新Request配置,但不太常用registerOptionsBeanDefinition(registry, contextId);
}
}

FeignClientFactoryBean的作用,实现了FactoryBean接口,会调用getObject方法创建bean。

publicclassFeignClientFactoryBeanimplementsFactoryBean<Object>, InitializingBean, ApplicationContextAware, BeanFactoryAware {
@OverridepublicObjectgetObject() {
returngetTarget();
}
<T> TgetTarget() {
/* 获取FeignContext,FeignContext继承了NamedContextFactory,它是用来统一维护feign中各个feign客户端相互隔离的上下文 FeignContext注册到容器是在FeignAutoConfiguration上完成的 */FeignContextcontext = beanFactory != null ? beanFactory.getBean(FeignContext.class)
: applicationContext.getBean(FeignContext.class);
// 构建feign.builder,在构建时会向FeignContext获取配置的Encoder,Decoder等各种信息// FeignContext会为每个Feign客户端分配一个容器,它们的父容器就是Spring容器。Feign.Builderbuilder = feign(context);
// 如果url为空,则走负载均衡,生成有负载均衡功能的代理类if (!StringUtils.hasText(url)) {
if (LOG.isInfoEnabled()) {
LOG.info("For '" + name + "' URL not provided. Will try picking an instance via load-balancing.");
}
if (!name.startsWith("http")) {
url = "http://" + name;
}
else {
url = name;
}
url += cleanPath();
// 创建 feign 客户端,@FeignClient 没有配置url属性,返回有负载均衡功能的代理对象return (T) loadBalance(builder, context, newHardCodedTarget<>(type, name, url));
}
// 如果指定了url,则生成默认的代理类if (StringUtils.hasText(url) && !url.startsWith("http")) {
url = "http://" + url;
}
Stringurl = this.url + cleanPath();
Clientclient = getOptional(context, Client.class);
if (client != null) {
if (clientinstanceofFeignBlockingLoadBalancerClient) {
// not load balancing because we have a url,// but Spring Cloud LoadBalancer is on the classpath, so unwrapclient = ((FeignBlockingLoadBalancerClient) client).getDelegate();
}
if (clientinstanceofRetryableFeignBlockingLoadBalancerClient) {
// not load balancing because we have a url,// but Spring Cloud LoadBalancer is on the classpath, so unwrapclient = ((RetryableFeignBlockingLoadBalancerClient) client).getDelegate();
}
builder.client(client);
}
Targetertargeter = get(context, Targeter.class);
return (T) targeter.target(this, builder, context, newHardCodedTarget<>(type, name, url));
}
protected <T> TloadBalance(Feign.Builderbuilder, FeignContextcontext, HardCodedTarget<T> target) {
// 从上下文中获取 Client,默认是 FeignBlockingLoadBalancerClient// 它是在 FeignLoadBalancerAutoConfiguration 这个自动装配类中,通过Import实现的// Client是根据serviceId(服务名)进行隔离的Clientclient = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
Targetertargeter = get(context, Targeter.class);
/* 默认实现是 DefaultTargeter 在OpenFeign低版本是HystrixTargeter,高版本移除了Hystrix,采用Spring Cloud Circuit Breaker 做限流熔断 */returntargeter.target(this, builder, context, target);
}
thrownewIllegalStateException(
"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?");
}
}

DefaultTargeter

classDefaultTargeterimplementsTargeter {
@Overridepublic <T> Ttarget(FeignClientFactoryBeanfactory, Feign.Builderfeign, FeignContextcontext,
Target.HardCodedTarget<T> target) {
returnfeign.target(target);
}
}

Feign

publicabstractclassFeign {
publicstaticclassBuilder {
public <T> Ttarget(Target<T> target) {
// 创建一个动态代理类,最终会调用 ReflectiveFeign.newInstancereturnbuild().newInstance(target);
}
publicFeignbuild() {
/* 在FeignClientFactoryBean#configureFeign中会把容器中的Capability设置进来 Capability对象可以增强Feign的各个组件,一般就是对原有的组件的包装 */Clientclient = Capability.enrich(this.client, capabilities);
Retryerretryer = Capability.enrich(this.retryer, capabilities);
List<RequestInterceptor> requestInterceptors = this.requestInterceptors.stream()
.map(ri -> Capability.enrich(ri, capabilities))
.collect(Collectors.toList());
Loggerlogger = Capability.enrich(this.logger, capabilities);
Contractcontract = Capability.enrich(this.contract, capabilities);
Optionsoptions = Capability.enrich(this.options, capabilities);
Encoderencoder = Capability.enrich(this.encoder, capabilities);
Decoderdecoder = Capability.enrich(this.decoder, capabilities);
InvocationHandlerFactoryinvocationHandlerFactory =
Capability.enrich(this.invocationHandlerFactory, capabilities);
QueryMapEncoderqueryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);
// 初始化SynchronousMethodHandler.Factory工厂,后续使用该工厂生成代理对象的方法SynchronousMethodHandler.FactorysynchronousMethodHandlerFactory =
newSynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
// 用来创建方法名与对应MethodHandler的映射关系ParseHandlersByNamehandlersByName =
newParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
// 创建一个动态代理类 ReflectiveFeignreturnnewReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
}
}

ReflectiveFeign.newInstance()

publicclassReflectiveFeignextendsFeign {
@Overridepublic <T> TnewInstance(Target<T> target) {
/* 根据接口类和 Contract 协议解析方式,解析接口类上的方法和注解(@RequestMapping...),转换成内部的 MethodHandler 处理方式 这里的 target 为 HardCodedTarget,包含了该feign客户端的接口类型,name,url等 用 ParseHandlersByName 创建方法名和MethodHandler的映射map */Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
// Method对象和MethodHandler的映射mapMap<Method, MethodHandler> methodToHandler = newLinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = newLinkedList<DefaultMethodHandler>();
// 遍历接口中的所有方法for (Methodmethod : target.type().getMethods()) {
if (method.getDeclaringClass() == Object.class) {
continue;
// 判断是不是接口中的默认方法
} elseif (Util.isDefault(method)) {
DefaultMethodHandlerhandler = newDefaultMethodHandler(method);
defaultMethodHandlers.add(handler);
methodToHandler.put(method, handler);
} else {
// 自定义的方法从 nameToHandler 里面获取对应的 SynchronousMethodHandlermethodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
// jdk动态代理 InvocationHandler,类型为 FeignCircuitBreakerInvocationHandlerInvocationHandlerhandler = factory.create(target, methodToHandler);
// 基于 JDK动态代理 为接口类创建动态实现,将所有的请求转换给 InvocationHandler 处理// 创建的是 ReflectiveFeign.FeignInvocationHandler 代理对象Tproxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
newClass<?>[] {target.type()}, handler);
for (DefaultMethodHandlerdefaultMethodHandler : defaultMethodHandlers) {
// 将 MethodHandle 绑定到代理对象defaultMethodHandler.bindTo(proxy);
}
returnproxy;
}
}

至此,FeignClient接口注入就分析完了,大致流程就是:

  1. 包扫描,扫描带有@FeignClient注解标识的接口。

  2. 根据接口信息封装为BeanDefinition。

  3. 在使用时,调用FactoryBean#getObject返回代理对象并注入到IOC容器中。

OpenFeign调用过程

前面创建的代理对象类型为 ReflectiveFeign.FeignInvocationHandler,所以当调用时,该代理对象的**invoke()**方法是调用入口。

publicclassReflectiveFeignextendsFeign {
staticclassFeignInvocationHandlerimplementsInvocationHandler {
@OverridepublicObjectinvoke(Objectproxy, Methodmethod, Object[] args) throwsThrowable {
if ("equals".equals(method.getName())) {
try {
ObjectotherHandler =
args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
returnequals(otherHandler);
} catch (IllegalArgumentExceptione) {
returnfalse;
}
} elseif ("hashCode".equals(method.getName())) {
returnhashCode();
} elseif ("toString".equals(method.getName())) {
returntoString();
}
// 这里的 dispatch 对象就是之前的 methodToHandler 方法与 SynchronousMethodHandler 的映射 map// 利用分发器找到处理目标方法的 handler,根据请求目标对应的url找到需要执行的方法进行调用// 在创建代理对象的时候,创建了一个动态代理的方法,其类型为 SynchronousMethodHandlerreturndispatch.get(method).invoke(args);
}
}
}

SynchronousMethodHandler.invoke(),该方法会根据参数生成完整的RequestTemplate对象,这个对象是HTTP请求的模板。

finalclassSynchronousMethodHandlerimplementsMethodHandler {
@OverridepublicObjectinvoke(Object[] argv) throwsThrowable {
// 获取 RequestTemplate 对象RequestTemplatetemplate = buildTemplateFromArgs.create(argv);
// 配置接口请求参数Optionsoptions = findOptions(argv);
// 重试器Retryerretryer = this.retryer.clone();
while (true) {
try {
// 请求的调用和处理响应returnexecuteAndDecode(template, options);
} catch (RetryableExceptione) {
try {
// 尝试重试和处理// 重试间隔按照1.5的倍数进行重试,如果超过重试设置的最大因子数则停止重试。retryer.continueOrPropagate(e);
} catch (RetryableExceptionth) {
Throwablecause = th.getCause();
if (propagationPolicy == UNWRAP && cause != null) {
throwcause;
} else {
throwth;
}
}
// 如果实现了日志类的打印,会打印日志信息if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}
}

executeAndDecode()

finalclassSynchronousMethodHandlerimplementsMethodHandler {
ObjectexecuteAndDecode(RequestTemplatetemplate, Optionsoptions) throwsThrowable {
// 获取 Request 对象,可以实现RequestInterceptor接口,对Request进⾏增强Requestrequest = targetRequest(template);
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}
Responseresponse;
longstart = System.nanoTime();
try {
/* 发起远程调用,这个 client 类型为是 FeignBlockingLoadBalancerClient FeignBlockingLoadBalancerClient 中的负载均衡客户端会改写url路径 */response = client.execute(request, options);
// ensure the request is set. TODO: remove in Feign 12response = response.toBuilder()
.request(request)
.requestTemplate(template)
.build();
} catch (IOExceptione) {
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
}
throwerrorExecuting(request, e);
}
longelapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
if (decoder != null)
returndecoder.decode(response, metadata.returnType());
CompletableFuture<Object> resultFuture = newCompletableFuture<>();
asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
metadata.returnType(),
elapsedTime);
try {
if (!resultFuture.isDone())
thrownewIllegalStateException("Response handling not done");
returnresultFuture.join();
} catch (CompletionExceptione) {
Throwablecause = e.getCause();
if (cause != null)
throwcause;
throwe;
}
}
}

FeignBlockingLoadBalancerClient#execute()

publicclassFeignBlockingLoadBalancerClientimplementsClient {
@OverridepublicResponseexecute(Requestrequest, Request.Optionsoptions) throwsIOException {
// 原始的url,一般为服务名 "http://orderService/user/1"finalURIoriginalUri = URI.create(request.url());
// 获取服务名 "orderService"StringserviceId = originalUri.getHost();
Assert.state(serviceId != null, "Request URI does not contain a valid hostname: " + originalUri);
Stringhint = getHint(serviceId);
DefaultRequest<RequestDataContext> lbRequest = newDefaultRequest<>(
newRequestDataContext(buildRequestData(request), hint));
Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator
.getSupportedLifecycleProcessors(
loadBalancerClientFactory.getInstances(serviceId, LoadBalancerLifecycle.class),
RequestDataContext.class, ResponseData.class, ServiceInstance.class);
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));
// 这个方法做了两件事:先找到负载均衡策略(默认轮询),再按负载均衡策略挑选实例// 使用负载均衡客户端根据服务名选择一个服务实例// 如果使用的是Nacos,则 choose 方法内部会调用 NacosLoadBalancer#choose 方法获取到服务列表// 然后根据负载策略选择最优实例ServiceInstanceinstance = loadBalancerClient.choose(serviceId, lbRequest);
org.springframework.cloud.client.loadbalancer.Response<ServiceInstance> lbResponse = newDefaultResponse(
instance);
if (instance == null) {
Stringmessage = "Load balancer does not contain an instance for the service " + serviceId;
if (LOG.isWarnEnabled()) {
LOG.warn(message);
}
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
.onComplete(newCompletionContext<ResponseData, ServiceInstance, RequestDataContext>(
CompletionContext.Status.DISCARD, lbRequest, lbResponse)));
returnResponse.builder().request(request).status(HttpStatus.SERVICE_UNAVAILABLE.value())
.body(message, StandardCharsets.UTF_8).build();
}
// 改写url,负载均衡器通过注册中心拉取的服务地址改写urlStringreconstructedUrl = loadBalancerClient.reconstructURI(instance, originalUri).toString();
// 使用改写过后的url构建一个新的requestRequestnewRequest = buildRequest(request, reconstructedUrl);
returnexecuteWithLoadBalancerLifecycleProcessing(delegate, options, newRequest, lbRequest, lbResponse,
supportedLifecycleProcessors);
}
}

LoadBalancerUtils#executeWithLoadBalancerLifecycleProcessing()

finalclassLoadBalancerUtils {
staticResponseexecuteWithLoadBalancerLifecycleProcessing(ClientfeignClient, Request.Optionsoptions,
RequestfeignRequest, org.springframework.cloud.client.loadbalancer.RequestlbRequest,
org.springframework.cloud.client.loadbalancer.Response<ServiceInstance> lbResponse,
Set<LoadBalancerLifecycle> supportedLifecycleProcessors) throwsIOException {
returnexecuteWithLoadBalancerLifecycleProcessing(feignClient, options, feignRequest, lbRequest, lbResponse,
supportedLifecycleProcessors, true);
}
staticResponseexecuteWithLoadBalancerLifecycleProcessing(ClientfeignClient, Request.Optionsoptions,
RequestfeignRequest, org.springframework.cloud.client.loadbalancer.RequestlbRequest,
org.springframework.cloud.client.loadbalancer.Response<ServiceInstance> lbResponse,
Set<LoadBalancerLifecycle> supportedLifecycleProcessors, booleanloadBalanced) throwsIOException {
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStartRequest(lbRequest, lbResponse));
try {
// 使用feignClient执行请求,这里默认是Client.Default,可以换成 httpclient 或 okhttp 等// 如果是Client.Default,会使用java自带的HttpURLConnection发送请求Responseresponse = feignClient.execute(feignRequest, options);
if (loadBalanced) {
supportedLifecycleProcessors.forEach(
lifecycle -> lifecycle.onComplete(newCompletionContext<>(CompletionContext.Status.SUCCESS,
lbRequest, lbResponse, buildResponseData(response))));
}
returnresponse;
}
catch (Exceptionexception) {
if (loadBalanced) {
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onComplete(
newCompletionContext<>(CompletionContext.Status.FAILED, exception, lbRequest, lbResponse)));
}
throwexception;
}
}
}

总结

Ribbon:也进入了维护状态,停止更新了,但是Spring官方推出了一个新的组件 LoadBalancer。

OpenFeign的源码体量相对较小,但想要用一篇文章来深入也不太现实,都是挑执行链路上的核心点进行剖析。

OpenFeign的底层原理大致如下:

  1. 通过@EnableFeignClients注解注入 OpenFeign 配置类。

  2. FeignClientsRegistrar 扫描包下所有的 @FeignClient 接口类,并将其注册到 IOC 容器。

  3. @FeignClient 接口类被注入时,通过FactoryBean#getObject返回动态代理类。

  4. 接口被调用时被动态代理类逻辑拦截,将 @FeignClient 请求信息通过编码器生成 Request。

  5. 由 Ribbon(Loadbalancer) 进行负载均衡,挑选出一个健康的 Server 实例。

  6. 通过 Client 携带 Request 调用远端服务,返回请求响应。

  7. 通过解码器生成 Response 返回客户端,将信息流解析成为接口返回数据。

如果使用的注册中心是Nacos,则Nacos会适配 Loadbalancer,当 Loadbalancer 获取可用服务时,实际上调用的是NacosLoadBalancer组件。