一 开启ApacheHttpClient
如果我们使用Apache的 HttpClient作为客户端的话,其实现逻辑就是这样的
@Configuration @ConditionalOnClass({ApacheHttpClient.class})//classpath下必须得有ApacheHttpClient @ConditionalOnProperty( value = {"feign.httpclient.enabled"}, matchIfMissing = true ) class HttpClientFeignLoadBalancedConfiguration { //空的构造器 HttpClientFeignLoadBalancedConfiguration() { } @Bean @ConditionalOnMissingBean({Client.class}) public Client feignClient( CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory, HttpClient httpClient) { ApacheHttpClient delegate = new ApacheHttpClient(httpClient); return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory); // 进行包装 } //…省略不相干的代码 }
pom文件里必须得有
<dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> <version>9.5.1</version> <!--<version>${feign-httpclient.version}</version>--> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency>
观察下LoadBalancerFeignClient的代码
public class LoadBalancerFeignClient implements Client { static final Request.Options DEFAULT_OPTIONS = new Request.Options(); private final Client delegate;//实现类就是ApacheHttpClient private CachingSpringLoadBalancerFactory lbClientFactory;//获取ILoadBalancer的工厂类,也是Feign和Ribbon关联的纽带 private SpringClientFactory clientFactory; public LoadBalancerFeignClient(Client delegate, CachingSpringLoadBalancerFactory lbClientFactory, SpringClientFactory clientFactory) { this.delegate = delegate; this.lbClientFactory = lbClientFactory; this.clientFactory = clientFactory; }
@ConditionalOnProperty(
value = {"feign.httpclient.enabled"},
matchIfMissing = true 说明其实我们可以不配 feign.httpclient.enabled,只要在classpath下有ApacheHttpClient该配置类就会生效了
二 Feign是怎么做负载均衡的
LoadBalancerFeignClient
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(); }
我这里截了个图
clientName就是服务名
经过转换原始的请求转成了FeignLoadBalancer.RibbonRequest
private FeignLoadBalancer lbClient(String clientName) { return this.lbClientFactory.create(clientName); }
clientName就是实际服务的名字
public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException { LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig); try { return command.submit( new ServerOperation<T>() { @Override public Observable<T> call(Server server) { URI finalUri = reconstructURIWithServer(server, request.getUri()); S requestForServer = (S) request.replaceUri(finalUri); try { return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig)); } catch (Exception e) { return Observable.error(e); } } }) .toBlocking() .single(); } catch (Exception e) { Throwable t = e.getCause(); if (t instanceof ClientException) { throw (ClientException) t; } else { throw new ClientException(e); } } }
LoadBalancerCommand.submit
public Observable<T> submit(final ServerOperation<T> operation) { final ExecutionInfoContext context = new ExecutionInfoContext(); if (listenerInvoker != null) { try { listenerInvoker.onExecutionStart(); } catch (AbortExecutionException e) { return Observable.error(e); } } final int maxRetrysSame = retryHandler.getMaxRetriesOnSameServer(); final int maxRetrysNext = retryHandler.getMaxRetriesOnNextServer(); // Use the load balancer Observable<T> o = (server == null ? selectServer() : Observable.just(server)) .concatMap(new Func1<Server, Observable<T>>() { @Override // Called for each server being selected public Observable<T> call(Server server) { context.setServer(server); final ServerStats stats = loadBalancerContext.getServerStats(server); // Called for each attempt and retry
private Observable<Server> selectServer() { return Observable.create(new OnSubscribe<Server>() { @Override public void call(Subscriber<? super Server> next) { try { Server server = loadBalancerContext.getServerFromLoadBalancer(loadBalancerURI, loadBalancerKey); next.onNext(server); next.onCompleted(); } catch (Exception e) { next.onError(e); } } }); }
LoadBalancerContext.getServerFromLoadBalancer
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 = deriveSchemeAndPortFromPartialUri(original); port = schemeAndPort.second(); } // Various Supported Cases // The loadbalancer to use and the instances it has is based on how it was registered // In each of these cases, the client might come in using Full Url or Partial URL ILoadBalancer lb = getLoadBalancer(); if (host == null) { // Partial URI or no URI Case // well we have to just get the right instances from lb - or we fall back if (lb != null){ Server svc = lb.chooseServer(loadBalancerKey);
ILoadBalancer 在介绍Ribbon那节就介绍过了,它是负责根据负载策略选择要发送的server的