一、Feign发起请求
Feign在初始化时通过jdk动态代理完成了被调用方法与SynchronousMethodHandler的键值对映射(参考Spring-Cloud-Feign源码阅读(1)-FeignClient是如何初始化的),在调用方法时就会调用SynchronousMethodHandler的invoke方法。
final class SynchronousMethodHandler implements MethodHandler {
...
public Object invoke(Object[] argv) throws Throwable {
//完成feignClient解析之后,调用之前的实际参数的绑定
RequestTemplate template = this.buildTemplateFromArgs.create(argv);
while(true) {
try {
//执行请求并进行解码
return this.executeAndDecode(template);
} catch (RetryableException var8) {
...
}
}
}
...
}
private static class BuildTemplateByResolvingArgs implements Factory {
...
public RequestTemplate create(Object[] argv) {
RequestTemplate mutable = RequestTemplate.from(this.metadata.template());
if (this.metadata.urlIndex() != null) {
int urlIndex = this.metadata.urlIndex();
Util.checkArgument(argv[urlIndex] != null, "URI parameter %s was null", new Object[]{urlIndex});
mutable.target(String.valueOf(argv[urlIndex]));
}
...
while(true) {
...
if (this.metadata.queryMapIndex() != null) {
Object value = argv[this.metadata.queryMapIndex()];
Map<String, Object> queryMap = this.toQueryMap(value);
//传入QueryMap参数
template = this.addQueryMapQueryParameters(queryMap, template);
}
if (this.metadata.headerMapIndex() != null) {
//传入HeaderMap参数
template = this.addHeaderMapHeaders((Map)argv[this.metadata.headerMapIndex()], template);
}
return template;
}
}
}
}
Object executeAndDecode(RequestTemplate template) throws Throwable {
//此方法执行拦截器的apply方法
Request request = this.targetRequest(template);
...
try {
//发起请求
response = this.client.execute(request, this.options);
} catch (IOException var15) {
if (this.logLevel != Level.NONE) {
this.logger.logIOException(this.metadata.configKey(), this.logLevel, var15, this.elapsedTime(start));
}
throw FeignException.errorExecuting(request, var15);
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
boolean shouldClose = true;
Object var10;
try {
//判断方法的返回类型 如果是Response.class,则不进行解码处理
if (Response.class == this.metadata.returnType()) {
Response var18;
if (response.body() == null) {
var18 = response;
return var18;
}
if (response.body().length() != null && (long)response.body().length() <= 8192L) {
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
Response var20 = response.toBuilder().body(bodyData).build();
return var20;
}
shouldClose = false;
var18 = response;
return var18;
}
//如果http响应状态码是成功,则进行解码
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;
var10 = result;
return var10;
}
//如果http响应状态码非404情况下用errorDecoder解码
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;
var10 = result;
} catch (IOException var16) {
if (this.logLevel != Level.NONE) {
this.logger.logIOException(this.metadata.configKey(), this.logLevel, var16, elapsedTime);
}
throw FeignException.errorReading(request, response, var16);
} finally {
if (shouldClose) {
Util.ensureClosed(response.body());
}
}
return var10;
}
Request targetRequest(RequestTemplate template) {
Iterator var2 = this.requestInterceptors.iterator();
while(var2.hasNext()) {
RequestInterceptor interceptor = (RequestInterceptor)var2.next();
interceptor.apply(template);
}
return this.target.apply(template);
}
feignClient方法在被调用之后,会执行到SynchronousMethodHandler的invoke方法,在绑定完实际参数之后,由LoadBalancerFeignClient发起请求,并根据返回类型进行解码。executeAndDecode之前的targetRequest会执行当前SynchronousMethodHandler的拦截器方法,但是在此处没有对拦截器进行排序,以初始化时List中的顺序为准。
二、Feign的httpClient
SynchronousMethodHandler的Object executeAndDecode(RequestTemplate template)方法里response = this.client.execute(request, this.options)发起请求,this.client默认情况下是LoadBalancerFeignClient,默认的httpClient是java.net.HttpURLConnection,也通过@Conditional系列注解实现了对org.apache.http.impl.client.CloseableHttpClient和okhttp3.OkHttpClient的支持。
@Configuration
class DefaultFeignLoadBalancedConfiguration {
@Bean
@ConditionalOnMissingBean
//new Client.Default默认使用的java.net.HttpURLConnection
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) {
return new LoadBalancerFeignClient(new Client.Default(null, null),
cachingFactory, clientFactory);
}
}
@ConditionalOnClass(ApacheHttpClient.class)
@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
class HttpClientFeignLoadBalancedConfiguration {
...
@Bean
@ConditionalOnMissingBean(Client.class)
//delegate是ApacheHttpClient
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory, HttpClient httpClient)
{
ApacheHttpClient delegate = new ApacheHttpClient(httpClient);
return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
}
}
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnProperty(value = "feign.okhttp.enabled")
class OkHttpFeignLoadBalancedConfiguration {
...
@Bean
@ConditionalOnMissingBean(Client.class)
//delegate是OkHttpClient
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory, okhttp3.OkHttpClient okHttpClient) {
OkHttpClient delegate = new OkHttpClient(okHttpClient);
return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
}
}
//Order is important here, last should be the default, first should be optional
// see https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653
@Import({ HttpClientFeignLoadBalancedConfiguration.class,
OkHttpFeignLoadBalancedConfiguration.class,
DefaultFeignLoadBalancedConfiguration.class })
三个httpclient的顺序如上,如果相关依赖包都引入,配置也加上的话,优先CloseableHttpClient,其次OkHttpClient,最后就是HttpURLConnection。
三、Feign集成Ribbon实现的客户端负载均衡
(1)LoadBalancerFeignClient
package org.springframework.cloud.openfeign.ribbon;
/**
* @author Dave Syer
*
*/
public class LoadBalancerFeignClient implements Client {
static final Request.Options DEFAULT_OPTIONS = new Request.Options();
//实现Client接口的类,CloseableHttpClient、OkHttpClient、HttpURLConnection之一
private final Client delegate;
//构建FeignLoadBalancer的工厂
private CachingSpringLoadBalancerFactory lbClientFactory;
//ribbon的NamedContextFactory
private SpringClientFactory clientFactory;
@Override
public Response execute(Request request, Request.Options options) throws IOException {
try {
//将url转换成asUri
URI asUri = URI.create(request.url());
//获取微服务名称
String clientName = asUri.getHost();
//去掉微服务名称后的uri
URI uriWithoutHost = cleanUrl(request.url(), clientName);
FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
this.delegate, request, uriWithoutHost);
//根据微服务名称获取相关的配置,这个对象很重要
IClientConfig requestConfig = getClientConfig(options, clientName);
//构建FeignLoadBalancer并发起调用
return lbClient(clientName).executeWithLoadBalancer(ribbonRequest,
requestConfig).toResponse();
}
catch (ClientException e) {
...
}
}
package org.springframework.cloud.openfeign.ribbon;
@Configuration
class DefaultFeignLoadBalancedConfiguration {
@Bean
@ConditionalOnMissingBean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) {
return new LoadBalancerFeignClient(new Client.Default(null, null),
cachingFactory, clientFactory);
}
}
(2)SpringClientFactory
package org.springframework.cloud.netflix.ribbon;
public class RibbonAutoConfiguration {
@Bean
public SpringClientFactory springClientFactory() {
SpringClientFactory factory = new SpringClientFactory();
factory.setConfigurations(this.configurations);
return factory;
}
}
(3)CachingSpringLoadBalancerFactory
针对每个clientName都会生成一个FeignLoadBalancer对象,并缓存到内存。注入时也会根据@ConditionalOnClass注解判断是否具有重试的功能。
package org.springframework.cloud.openfeign.ribbon;
public class CachingSpringLoadBalancerFactory {
protected final SpringClientFactory factory;
protected LoadBalancedRetryFactory loadBalancedRetryFactory = null;
private volatile Map<String, FeignLoadBalancer> cache = new ConcurrentReferenceHashMap<>();
...
//构建FeignLoadBalancer对象
public FeignLoadBalancer create(String clientName) {
FeignLoadBalancer client = this.cache.get(clientName);
if(client != null) {
return client;
}
//获取ClientConfig 这个对象很重要
IClientConfig config = this.factory.getClientConfig(clientName);
//ILoadBalancer获取ribbon的负载均衡 这个对象很重要
ILoadBalancer lb = this.factory.getLoadBalancer(clientName);
ServerIntrospector serverIntrospector = this.factory.getInstance(clientName, ServerIntrospector.class);
//判断是否有重试的工厂
client = loadBalancedRetryFactory != null ? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,
loadBalancedRetryFactory) : new FeignLoadBalancer(lb, config, serverIntrospector);
this.cache.put(clientName, client);
return client;
}
}
package org.springframework.cloud.openfeign.ribbon;
public class FeignRibbonClientAutoConfiguration {
@Bean
@Primary
@ConditionalOnMissingBean
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
public CachingSpringLoadBalancerFactory cachingLBClientFactory(
SpringClientFactory factory) {
return new CachingSpringLoadBalancerFactory(factory);
}
@Bean
@Primary
@ConditionalOnMissingBean
@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
public CachingSpringLoadBalancerFactory retryabeCachingLBClientFactory(
SpringClientFactory factory,
LoadBalancedRetryFactory retryFactory) {
return new CachingSpringLoadBalancerFactory(factory, retryFactory);
}
}
(4)FeignLoadBalancer
仅有一个execute方法,executeWithLoadBalancer方法在其父类AbstractLoadBalancerAwareClient。
package org.springframework.cloud.openfeign.ribbon;
public class FeignLoadBalancer extends
AbstractLoadBalancerAwareClient<FeignLoadBalancer.RibbonRequest, FeignLoadBalancer.RibbonResponse> {
private final RibbonProperties ribbon;
protected int connectTimeout;
protected int readTimeout;
protected IClientConfig clientConfig;
protected ServerIntrospector serverIntrospector;
@Override
public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride)
throws IOException {
Request.Options options;
if (configOverride != null) {
RibbonProperties override = RibbonProperties.from(configOverride);
options = new Request.Options(
override.connectTimeout(this.connectTimeout),
override.readTimeout(this.readTimeout));
}
else {
options = new Request.Options(this.connectTimeout, this.readTimeout);
}
Response response = request.client().execute(request.toRequest(), options);
return new RibbonResponse(request.getUri(), response);
}
}
package com.netflix.client;
public abstract class AbstractLoadBalancerAwareClient<S extends ClientRequest, T extends IResponse> extends LoadBalancerContext implements IClient<S, T>, IClientConfigAware {
public AbstractLoadBalancerAwareClient(ILoadBalancer lb) {
super(lb);
}
public T executeWithLoadBalancer(S request) throws ClientException {
return this.executeWithLoadBalancer(request, (IClientConfig)null);
}
public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
LoadBalancerCommand command = this.buildLoadBalancerCommand(request, requestConfig);
try {
//使用rxjava响应式编程,command.submit内部会进行客户端负载均衡选择出适合的Server再进行调用执行
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 {
//调用子类的execute方法
return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
} catch (Exception var5) {
return Observable.error(var5);
}
}
}).toBlocking().single();
} catch (Exception var6) {
...
}
}
public class LoadBalancerCommand<T> {
private final URI loadBalancerURI;
private final Object loadBalancerKey;
private final LoadBalancerContext loadBalancerContext;
private final RetryHandler retryHandler;
private volatile ExecutionInfo executionInfo;
private final Server server;
private final ExecutionContextListenerInvoker<?, T> listenerInvoker;
private Observable<Server> selectServer() {
return Observable.create(new OnSubscribe<Server>() {
public void call(Subscriber<? super Server> next) {
try {
Server server = LoadBalancerCommand.this.loadBalancerContext.getServerFromLoadBalancer(LoadBalancerCommand.this.loadBalancerURI, LoadBalancerCommand.this.loadBalancerKey);
next.onNext(server);
next.onCompleted();
} catch (Exception var3) {
next.onError(var3);
}
}
});
}
public Observable<T> submit(final ServerOperation<T> operation) {
...//这段代码真没看懂
Observable<T> o = (this.server == null ? this.selectServer() : Observable.just(this.server)).concatMap(new Func1<Server, Observable<T>>() {
public Observable<T> call(Server server) {
...
}
});
}
submit方法调用私有的selectServer(),再调用LoadBalancerContext的getServerFromLoadBalancer方法。
public class LoadBalancerContext implements IClientConfigAware {
public Server getServerFromLoadBalancer(@Nullable URI original, @Nullable Object loadBalancerKey) throws ClientException {
String host = null;
int port = -1;
if (original != null) {
host = original.getHost();
}
if (original != null) {
Pair<String, Integer> schemeAndPort = this.deriveSchemeAndPortFromPartialUri(original);
port = (Integer)schemeAndPort.second();
}
ILoadBalancer lb = this.getLoadBalancer();
if (host == null) {
if (lb != null) {
//调用ILoadBalancer的chooseServer方法
Server svc = lb.chooseServer(loadBalancerKey);
...
}
}
}
}
(5)ILoadBalancer的默认实例ZoneAwareLoadBalancer
package org.springframework.cloud.netflix.ribbon;
@Configuration
@EnableConfigurationProperties
@Import({HttpClientConfiguration.class, OkHttpRibbonConfiguration.class, RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class})
public class RibbonClientConfiguration {
@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config, ServerList<Server> serverList, ServerListFilter<Server> serverListFilter, IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
//没有特殊配置的话,实例化一个ZoneAwareLoadBalancer对象
return (ILoadBalancer)(this.propertiesFactory.isSet(ILoadBalancer.class, this.name) ? (ILoadBalancer)this.propertiesFactory.get(ILoadBalancer.class, config, this.name) : new ZoneAwareLoadBalancer(config, rule, ping, serverList, serverListFilter, serverListUpdater));
}
}
package com.netflix.loadbalancer;
public class BaseLoadBalancer extends AbstractLoadBalancer implements PrimeConnectionListener, IClientConfigAware {
protected IRule rule;
//所有server和上线的server存到内存里
@Monitor(
name = "LoadBalancer_AllServerList",
type = DataSourceType.INFORMATIONAL
)
protected volatile List<Server> allServerList;
@Monitor(
name = "LoadBalancer_UpServerList",
type = DataSourceType.INFORMATIONAL
)
protected volatile List<Server> upServerList;
//新增servers的方法
public void addServers(List<Server> newServers) {
}
public Server chooseServer(Object key) {
if (this.counter == null) {
this.counter = this.createCounter();
}
this.counter.increment();
if (this.rule == null) {
return null;
} else {
try {
//在调用成员变量Irule的choose方法
return this.rule.choose(key);
} catch (Exception var3) {
logger.warn("LoadBalancer [{}]: Error choosing server for key {}", new Object[]{this.name, key, var3});
return null;
}
}
}
}
public class DynamicServerListLoadBalancer<T extends Server> extends BaseLoadBalancer {
protected final UpdateAction updateAction;
public DynamicServerListLoadBalancer(IClientConfig clientConfig) {
this.isSecure = false;
this.useTunnel = false;
this.serverListUpdateInProgress = new AtomicBoolean(false);
class NamelessClass_1 implements UpdateAction {
NamelessClass_1() {
}
public void doUpdate() {
DynamicServerListLoadBalancer.this.updateListOfServers();
}
}
//定义更新Action动账的匿名类
this.updateAction = new NamelessClass_1();
this.initWithNiwsConfig(clientConfig);
}
@VisibleForTesting
public void updateListOfServers() {
List<T> servers = new ArrayList();
if (this.serverListImpl != null) {
//根据微服务名称获取最新的Servers
servers = this.serverListImpl.getUpdatedListOfServers();
LOGGER.debug("List of Servers for {} obtained from Discovery client: {}", this.getIdentifier(), servers);
if (this.filter != null) {
servers = this.filter.getFilteredListOfServers((List)servers);
LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}", this.getIdentifier(), servers);
}
}
//更新Servers
this.updateAllServerList((List)servers);
}
protected void updateAllServerList(List<T> ls) {
//使用cas防止并发
if (this.serverListUpdateInProgress.compareAndSet(false, true)) {
try {
Iterator var2 = ls.iterator();
while(var2.hasNext()) {
T s = (Server)var2.next();
s.setAlive(true);
}
//重新设置ServersList
this.setServersList(ls);
super.forceQuickPing();
} finally {
this.serverListUpdateInProgress.set(false);
}
}
}
public void setServersList(List lsrv) {
super.setServersList(lsrv);
Map<String, List<Server>> serversInZones = new HashMap();
Iterator var4 = lsrv.iterator();
//将ServerList按照zone区分开
while(var4.hasNext()) {
Server server = (Server)var4.next();
this.getLoadBalancerStats().getSingleServerStat(server);
String zone = server.getZone();
if (zone != null) {
zone = zone.toLowerCase();
List<Server> servers = (List)serversInZones.get(zone);
if (servers == null) {
servers = new ArrayList();
serversInZones.put(zone, servers);
}
((List)servers).add(server);
}
}
//ZoneAwareLoadBalancer重写了该方法
this.setServerListForZones(serversInZones);
}
}
package com.netflix.loadbalancer;
public class ZoneAwareLoadBalancer<T extends Server> extends DynamicServerListLoadBalancer<T> {
//重写父类的chooseServer
public Server chooseServer(Object key) {
if (ENABLED.get() && this.getLoadBalancerStats().getAvailableZones().size() > 1) {
Server server = null;
try {
LoadBalancerStats lbStats = this.getLoadBalancerStats();
Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats);
logger.debug("Zone snapshots: {}", zoneSnapshot);
if (this.triggeringLoad == null) {
this.triggeringLoad = DynamicPropertyFactory.getInstance().getDoubleProperty("ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".triggeringLoadPerServerThreshold", 0.2D);
}
if (this.triggeringBlackoutPercentage == null) {
this.triggeringBlackoutPercentage = DynamicPropertyFactory.getInstance().getDoubleProperty("ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".avoidZoneWithBlackoutPercetage", 0.99999D);
}
Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, this.triggeringLoad.get(), this.triggeringBlackoutPercentage.get());
logger.debug("Available zones: {}", availableZones);
if (availableZones != null && availableZones.size() < zoneSnapshot.keySet().size()) {
String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);
logger.debug("Zone chosen: {}", zone);
if (zone != null) {
//根据zone从map里获取BaseLoadBalancer,再调用BaseLoadBalancer的chooseServer方法
BaseLoadBalancer zoneLoadBalancer = this.getLoadBalancer(zone);
server = zoneLoadBalancer.chooseServer(key);
}
}
} catch (Exception var8) {
logger.error("Error choosing server using zone aware logic for load balancer={}", this.name, var8);
}
if (server != null) {
return server;
} else {
//如果筛选出的server是空则会调用父类的chooseServer方法
logger.debug("Zone avoidance logic is not invoked.");
return super.chooseServer(key);
}
} else {
logger.debug("Zone aware logic disabled or there is only one zone");
return super.chooseServer(key);
}
}
}
(6)IRule的默认实例ZoneAvoidanceRule
@Configuration
@EnableConfigurationProperties
@Import({HttpClientConfiguration.class, OkHttpRibbonConfiguration.class, RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class})
public class RibbonClientConfiguration {
@Bean
@ConditionalOnMissingBean
public IRule ribbonRule(IClientConfig config) {
if (this.propertiesFactory.isSet(IRule.class, this.name)) {
return (IRule)this.propertiesFactory.get(IRule.class, config, this.name);
} else {
ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
rule.initWithNiwsConfig(config);
return rule;
}
}
}
package com.netflix.loadbalancer;
public interface IRule {
//选择一个server
Server choose(Object var1);
//设置一个ILoadBalancer ILoadBalancer对象有serverList
void setLoadBalancer(ILoadBalancer var1);
ILoadBalancer getLoadBalancer();
}
package com.netflix.loadbalancer;
public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {
private ILoadBalancer lb;
public AbstractLoadBalancerRule() {
}
public void setLoadBalancer(ILoadBalancer lb) {
this.lb = lb;
}
public ILoadBalancer getLoadBalancer() {
return this.lb;
}
}
package com.netflix.loadbalancer;
public abstract class PredicateBasedRule extends ClientConfigEnabledRoundRobinRule {
public PredicateBasedRule() {
}
//抽象方法设置断言
public abstract AbstractServerPredicate getPredicate();
public Server choose(Object key) {
//从ILoadBalancer获取所有的server
ILoadBalancer lb = this.getLoadBalancer();
//调用断言的chooseRoundRobinAfterFiltering 选择合适的Server
Optional<Server> server = this.getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
return server.isPresent() ? (Server)server.get() : null;
}
}
public class ZoneAvoidanceRule extends PredicateBasedRule {
private static final Random random = new Random();
private CompositePredicate compositePredicate;
public ZoneAvoidanceRule() {
ZoneAvoidancePredicate zonePredicate = new ZoneAvoidancePredicate(this);
AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this);
//创建一个ZoneAvoidancePredicate 和 AvailabilityPredicate 组成的组合断言
this.compositePredicate = this.createCompositePredicate(zonePredicate, availabilityPredicate);
}
public AbstractServerPredicate getPredicate() {
return this.compositePredicate;
}
}
(7)Predicate
package com.netflix.loadbalancer;
public abstract class AbstractServerPredicate implements Predicate<PredicateKey> {
public List<Server> getEligibleServers(List<Server> servers, Object loadBalancerKey) {
if (loadBalancerKey == null) {
return ImmutableList.copyOf(Iterables.filter(servers, this.getServerOnlyPredicate()));
} else {
List<Server> results = Lists.newArrayList();
Iterator var4 = servers.iterator();
//通过断言的apply方法从所有的server筛选出合格的server
while(var4.hasNext()) {
Server server = (Server)var4.next();
if (this.apply(new PredicateKey(loadBalancerKey, server))) {
results.add(server);
}
}
return results;
}
}
public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
//筛选出合格的server之后做一个轮询
List<Server> eligible = this.getEligibleServers(servers, loadBalancerKey);
return eligible.size() == 0 ? Optional.absent() : Optional.of(eligible.get(this.incrementAndGetModulo(eligible.size())));
}
}
package com.netflix.loadbalancer;
public class CompositePredicate extends AbstractServerPredicate {
//组合多个断言
public static CompositePredicate.Builder withPredicates(AbstractServerPredicate... primaryPredicates) {
return new CompositePredicate.Builder(primaryPredicates);
}
public static class Builder {
private CompositePredicate toBuild = new CompositePredicate();
Builder(AbstractServerPredicate primaryPredicate) {
this.toBuild.delegate = primaryPredicate;
}
//多个断言之间是and关系
Builder(AbstractServerPredicate... primaryPredicates) {
Predicate<PredicateKey> chain = Predicates.and(primaryPredicates);
this.toBuild.delegate = AbstractServerPredicate.ofKeyPredicate(chain);
}
}
private static class AndPredicate<T> implements Predicate<T>, Serializable {
private final List<? extends Predicate<? super T>> components;
private static final long serialVersionUID = 0L;
private AndPredicate(List<? extends Predicate<? super T>> components) {
this.components = components;
}
//AndPredicate 多个断言都为true
public boolean apply(@Nullable T t) {
for(int i = 0; i < this.components.size(); ++i) {
if (!((Predicate)this.components.get(i)).apply(t)) {
return false;
}
}
return true;
}
}
}
package com.netflix.loadbalancer;
public class AvailabilityPredicate extends AbstractServerPredicate {
public boolean apply(@Nullable PredicateKey input) {
LoadBalancerStats stats = this.getLBStats();
if (stats == null) {
return true;
} else {
return !this.shouldSkipServer(stats.getSingleServerStat(input.getServer()));
}
}
private boolean shouldSkipServer(ServerStats stats) {
//判断server是否熔断或者超过了最大连接数限制
return CIRCUIT_BREAKER_FILTERING.get() && stats.isCircuitBreakerTripped() || stats.getActiveRequestsCount() >= (Integer)this.activeConnectionsLimit.get();
}
}
package com.netflix.loadbalancer;
public class ZoneAvoidancePredicate extends AbstractServerPredicate {
private volatile DynamicDoubleProperty triggeringLoad = new DynamicDoubleProperty("ZoneAwareNIWSDiscoveryLoadBalancer.triggeringLoadPerServerThreshold", 0.2D);
private volatile DynamicDoubleProperty triggeringBlackoutPercentage = new DynamicDoubleProperty("ZoneAwareNIWSDiscoveryLoadBalancer.avoidZoneWithBlackoutPercetage", 0.99999D);
public boolean apply(@Nullable PredicateKey input) {
//判断启用
if (!ENABLED.get()) {
return true;
} else {
String serverZone = input.getServer().getZone();
if (serverZone == null) {
return true;
} else {
LoadBalancerStats lbStats = this.getLBStats();
if (lbStats == null) {
return true;
} else if (lbStats.getAvailableZones().size() <= 1) {
return true;
} else {
Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats);
if (!zoneSnapshot.keySet().contains(serverZone)) {
return true;
} else {
logger.debug("Zone snapshots: {}", zoneSnapshot);
//根据triggeringLoad和triggeringBlackoutPercentage进行可用性判断,并避免不可用的服务
Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, this.triggeringLoad.get(), this.triggeringBlackoutPercentage.get());
logger.debug("Available zones: {}", availableZones);
return availableZones != null ? availableZones.contains(input.getServer().getZone()) : false;
}
}
}
}
}
}
四、总结
feign在调用过程会分为以下步骤
(1)完成RequestTemplate的实参绑定。
(2)调用拦截器的RequestInterceptor方法,可以对RequestTemplate进行一些修改。
(3)进行负载均衡选择合适的server,由ILoadBalance提供serverList,由Predicate对serverList进行过滤,由IRule是选择server。对于几个关键的对象的关系如下
①针对每一个微服务,都会有一个FeignLoadBalancer对象,并且每个FeignLoadBalancer对象都有一个ZoneAwareLoadBalancer对象。
②ZoneAwareLoadBalancer继承了BaseloadBalancer,把ServerList存到内存里。每个ZoneAwareLoadBalancer对象通过ConcurrentHashMap的形式维护了不用的zone有不同的BaseloadBalancer,key为zone,value为BaseloadBalancer。并且ZoneAwareLoadBalancer继承了DynamicServerListLoadBalancer,会有一个线程每隔一段时间从注册中心获取最新的server,并按照zone更新到ZoneAwareLoadBalancer对象的ConcurrentHashMap内。ZoneAwareLoadBalancer重写了BaseloadBalancer的Server chooseServer(Object key),会根据zone从ConcurrentHashMap获取BaseloadBalancer再调用chooseServer方法,如果选择的Servr是空,则会调用父类的chooseServer,通过这种方式保证了相同zone的优先调用。BaseloadBalancer的chooseServer会调用成员变量IRule的choose方法。
③默认初始化的IRule的实例是ZoneAvoidanceRule实例。ZoneAvoidanceRule继承了PredicateBasedRule,会调用成员变量的AbstractServerPredicate的chooseRoundRobinAfterFiltering方法选择Server,就是调用Predicate的apply方法过滤掉一部分Server再进行轮询。ZoneAvoidanceRule组合了ZoneAvoidancePredicate和AvailabilityPredicate两个断言。
④AvailabilityPredicate会判断熔断以及最大连接数,ZoneAvoidancePredicate会根据triggeringLoad和triggeringBlackoutPercentage判断可用并进行zone的判断。
(4)发起http请求并根据状态码进行decode。