电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

Spring Cloud Feign內部實現代碼細節

瀏覽:6日期:2023-07-14 14:57:44
1. 概述

Feign用于服務間調用,它的內部實現是一個包含Ribbon(負載均衡)的**JDK-HttpURLConnection(Http)**調用。雖然調用形式是類似于RPC,但是實際調用是Http,這也是為什么Feign被稱為偽RPC調用的原因。內部調用過程如下:

Spring Cloud Feign內部實現代碼細節

2. 代碼細節

1) BaseLoadBalancer.java配置初始化

重點功能: 1. 初始化負載均衡策略 2. 初始化取服務注冊列表調度策略

void initWithConfig(IClientConfig clientConfig, IRule rule, IPing ping, LoadBalancerStats stats) { ... // 每隔30s Ping一次 int pingIntervalTime = Integer.parseInt('' + clientConfig.getProperty( CommonClientConfigKey.NFLoadBalancerPingInterval, Integer.parseInt('30'))); // 每次最多Ping 2s int maxTotalPingTime = Integer.parseInt('' + clientConfig.getProperty( CommonClientConfigKey.NFLoadBalancerMaxTotalPingTime, Integer.parseInt('2'))); setPingInterval(pingIntervalTime); setMaxTotalPingTime(maxTotalPingTime); // cross associate with each other // i.e. Rule,Ping meet your container LB // LB, these are your Ping and Rule guys ... // 設置負載均衡規則 setRule(rule); // 初始化取服務注冊列表調度策略 setPing(ping); setLoadBalancerStats(stats); rule.setLoadBalancer(this); ...}

2) 負載均衡策略初始化

重點功能: 1. 默認使用輪詢策略

BaseLoadBalancer.java

public void setRule(IRule rule) { if (rule != null) {this.rule = rule; } else {/* default rule */// 默認使用輪詢策略this.rule = new RoundRobinRule(); } if (this.rule.getLoadBalancer() != this) {this.rule.setLoadBalancer(this); }}

RoundRobinRule.java

private AtomicInteger nextServerCyclicCounter;public Server choose(ILoadBalancer lb, Object key) { if (lb == null) {log.warn('no load balancer');return null; } Server server = null; int count = 0; while (server == null && count++ < 10) {List<Server> reachableServers = lb.getReachableServers();List<Server> allServers = lb.getAllServers();int upCount = reachableServers.size();int serverCount = allServers.size();if ((upCount == 0) || (serverCount == 0)) { log.warn('No up servers available from load balancer: ' + lb); return null;}// 輪詢重點算法int nextServerIndex = incrementAndGetModulo(serverCount);server = allServers.get(nextServerIndex);if (server == null) { /* Transient. */ Thread.yield(); continue;}if (server.isAlive() && (server.isReadyToServe())) { return (server);}// Next.server = null; } if (count >= 10) {log.warn('No available alive servers after 10 tries from load balancer: '+ lb); } return server;}private int incrementAndGetModulo(int modulo) { for (;;) {int current = nextServerCyclicCounter.get();int next = (current + 1) % modulo;if (nextServerCyclicCounter.compareAndSet(current, next)) return next; }}

3) 初始化取服務注冊列表調度策略

重點功能: 1. 設置輪詢間隔為30s 一次

注意: 這里沒有做實際的Ping,只是獲取緩存的注冊列表的alive服務,原因是為了提高性能

BaseLoadBalancer.java

public void setPing(IPing ping) { if (ping != null) {if (!ping.equals(this.ping)) { this.ping = ping; setupPingTask(); // since ping data changed} } else {this.ping = null;// cancel the timer tasklbTimer.cancel(); }}void setupPingTask() { if (canSkipPing()) {return; } if (lbTimer != null) {lbTimer.cancel(); } lbTimer = new ShutdownEnabledTimer('NFLoadBalancer-PingTimer-' + name, true); // 這里雖然默認設置是10s一次,但是在初始化的時候,設置了30s一次 lbTimer.schedule(new PingTask(), 0, pingIntervalSeconds * 1000); forceQuickPing();}class Pinger { private final IPingStrategy pingerStrategy; public Pinger(IPingStrategy pingerStrategy) {this.pingerStrategy = pingerStrategy; } public void runPinger() throws Exception {if (!pingInProgress.compareAndSet(false, true)) { return; // Ping in progress - nothing to do}// we are 'in' - we get to PingServer[] allServers = null;boolean[] results = null;Lock allLock = null;Lock upLock = null;try { /* * The readLock should be free unless an addServer operation is * going on... */ allLock = allServerLock.readLock(); allLock.lock(); allServers = allServerList.toArray(new Server[allServerList.size()]); allLock.unlock(); int numCandidates = allServers.length; results = pingerStrategy.pingServers(ping, allServers); final List<Server> newUpList = new ArrayList<Server>(); final List<Server> changedServers = new ArrayList<Server>(); for (int i = 0; i < numCandidates; i++) {boolean isAlive = results[i];Server svr = allServers[i];boolean oldIsAlive = svr.isAlive();svr.setAlive(isAlive);if (oldIsAlive != isAlive) { changedServers.add(svr); logger.debug('LoadBalancer [{}]: Server [{}] status changed to {}', name, svr.getId(), (isAlive ? 'ALIVE' : 'DEAD'));}if (isAlive) { newUpList.add(svr);} } upLock = upServerLock.writeLock(); upLock.lock(); upServerList = newUpList; upLock.unlock(); notifyServerStatusChangeListener(changedServers);} finally { pingInProgress.set(false);} }}private static class SerialPingStrategy implements IPingStrategy { @Override public boolean[] pingServers(IPing ping, Server[] servers) {int numCandidates = servers.length;boolean[] results = new boolean[numCandidates];logger.debug('LoadBalancer: PingTask executing [{}] servers configured', numCandidates);for (int i = 0; i < numCandidates; i++) { results[i] = false; /* Default answer is DEAD. */ try {// NOTE: IFF we were doing a real ping// assuming we had a large set of servers (say 15)// the logic below will run them serially// hence taking 15 times the amount of time it takes// to ping each server// A better method would be to put this in an executor// pool// But, at the time of this writing, we dont REALLY// use a Real Ping (its mostly in memory eureka call)// hence we can afford to simplify this design and run// this// seriallyif (ping != null) { results[i] = ping.isAlive(servers[i]);} } catch (Exception e) {logger.error('Exception while pinging Server: ’{}’', servers[i], e); }}return results; }}

4) 最后拼接完整URL使用JDK-HttpURLConnection進行調用

SynchronousMethodHandler.java(io.github.openfeign:feign-core:10.10.1/feign.SynchronousMethodHandler.java)

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 {response = this.client.execute(request, options);response = response.toBuilder().request(request).requestTemplate(template).build(); } catch (IOException var13) {if (this.logLevel != Level.NONE) { this.logger.logIOException(this.metadata.configKey(), this.logLevel, var13, this.elapsedTime(start));}throw FeignException.errorExecuting(request, var13); } ...}

LoadBalancerFeignClient.java

@Overridepublic 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); }}

AbstractLoadBalancerAwareClient.java

public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException { LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig); try {return command.submit( new ServerOperation<T>() {@Overridepublic Observable<T> call(Server server) { // 獲取真實訪問URL 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);} } }

FeignLoadBalancer.java

@Overridepublic 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);}

feign.Client.java

@Overridepublic Response execute(Request request, Options options) throws IOException { HttpURLConnection connection = convertAndSend(request, options); return convertResponse(connection, request);}Response convertResponse(HttpURLConnection connection, Request request) throws IOException { // 使用HttpURLConnection 真實進行Http調用 int status = connection.getResponseCode(); String reason = connection.getResponseMessage(); if (status < 0) { throw new IOException(format('Invalid status(%s) executing %s %s', status,connection.getRequestMethod(), connection.getURL())); } Map<String, Collection<String>> headers = new LinkedHashMap<>(); for (Map.Entry<String, List<String>> field : connection.getHeaderFields().entrySet()) { // response message if (field.getKey() != null) { headers.put(field.getKey(), field.getValue()); } } Integer length = connection.getContentLength(); if (length == -1) { length = null; } InputStream stream; if (status >= 400) { stream = connection.getErrorStream(); } else { stream = connection.getInputStream(); } return Response.builder() .status(status) .reason(reason) .headers(headers) .request(request) .body(stream, length) .build();}

拓展干貨閱讀:一線大廠面試題、高并發等主流技術資料

以上就是Spring Cloud Feign內部實現代碼細節的詳細內容,更多關于Spring Cloud Feign的資料請關注好吧啦網其它相關文章!

標簽: Spring
相關文章:
主站蜘蛛池模板: 密集架-密集柜厂家-智能档案密集架-自动选层柜订做-河北风顺金属制品有限公司 | 大通天成企业资质代办_承装修试电力设施许可证_增值电信业务经营许可证_无人机运营合格证_广播电视节目制作许可证 | 雾度仪_雾度计_透光率雾度仪价格-三恩时(3nh)光电雾度仪厂家 | 苏州注册公司_苏州代理记账_苏州工商注册_苏州代办公司-恒佳财税 | 废旧物资回收公司_广州废旧设备回收_报废设备物资回收-益美工厂设备回收公司 | 新疆十佳旅行社_新疆旅游报价_新疆自驾跟团游-新疆中西部国际旅行社 | 对照品_中药对照品_标准品_对照药材_「格利普」高纯中药标准品厂家-成都格利普生物科技有限公司 澳门精准正版免费大全,2025新澳门全年免费,新澳天天开奖免费资料大全最新,新澳2025今晚开奖资料,新澳马今天最快最新图库 | 查分易-成绩发送平台官网 | 不锈钢管件(不锈钢弯头,不锈钢三通,不锈钢大小头),不锈钢法兰「厂家」-浙江志通管阀 | 河北码上网络科技|邯郸小程序开发|邯郸微信开发|邯郸网站建设 | 水质监测站_水质在线分析仪_水质自动监测系统_多参数水质在线监测仪_水质传感器-山东万象环境科技有限公司 | 亚克力制品定制,上海嘉定有机玻璃加工制作生产厂家—官网 | 天津电机维修|水泵维修-天津晟佳机电设备有限公司 | 除尘器布袋骨架,除尘器滤袋,除尘器骨架,电磁脉冲阀膜片,卸灰阀,螺旋输送机-泊头市天润环保机械设备有限公司 | 胜为光纤光缆_光纤跳线_单模尾纤_光纤收发器_ODF光纤配线架厂家直销_北京睿创胜为科技有限公司 - 北京睿创胜为科技有限公司 | 橡胶接头|可曲挠橡胶接头|橡胶软接头安装使用教程-上海松夏官方网站 | 油漆辅料厂家_阴阳脚线_艺术漆厂家_内外墙涂料施工_乳胶漆专用防霉腻子粉_轻质粉刷石膏-魔法涂涂 | 洁净化验室净化工程_成都实验室装修设计施工_四川华锐净化公司 | 脱硝喷枪-氨水喷枪-尿素喷枪-河北思凯淋环保科技有限公司 | 柔软云母板-硬质-水位计云母片组件-首页-武汉长丰云母绝缘材料有限公司 | 刘秘书_你身边专业的工作范文写作小秘书 | 湖南自考_湖南自学考试网| 青岛代理记账_青岛李沧代理记账公司_青岛崂山代理记账一个月多少钱_青岛德辉财税事务所官网 | 螺旋绞龙叶片,螺旋输送机厂家,山东螺旋输送机-淄博长江机械制造有限公司 | 拖鞋定制厂家-品牌拖鞋代加工厂-振扬实业中国高端拖鞋大型制造商 | Copeland/谷轮压缩机,谷轮半封闭压缩机,谷轮涡旋压缩机,型号规格,技术参数,尺寸图片,价格经销商 CTP磁天平|小电容测量仪|阴阳极极化_双液系沸点测定仪|dsj电渗实验装置-南京桑力电子设备厂 | 济南保安公司加盟挂靠-亮剑国际安保服务集团总部-山东保安公司|济南保安培训学校 | 安徽集装箱厂-合肥国彩钢结构板房工程有限公司 | 旋片真空泵_真空泵_水环真空泵_真空机组-深圳恒才机电设备有限公司 | 重庆波纹管|重庆钢带管|重庆塑钢管|重庆联进管道有限公司 | 爆炸冲击传感器-无线遥测传感器-航天星百科 | 耐破强度测试仪-纸箱破裂强度试验机-济南三泉中石单品站 | 环氧铁红防锈漆_环氧漆_无溶剂环氧涂料_环氧防腐漆-华川涂料 | 艾默生变频器,艾默生ct,变频器,ct驱动器,广州艾默生变频器,供水专用变频器,风机变频器,电梯变频器,艾默生变频器代理-广州市盟雄贸易有限公司官方网站-艾默生变频器应用解决方案服务商 | 哈希PC1R1A,哈希CA9300,哈希SC4500-上海鑫嵩实业有限公司 | 视频教程导航网_视频教程之家_视频教程大全_最新视频教程分享发布平台 | 数显恒温培养摇床-卧式/台式恒温培养摇床|朗越仪器 | 光照全温振荡器(智能型)-恒隆仪器 | 生鲜配送系统-蔬菜食材配送管理系统-连锁餐饮订货配送软件-挪挪生鲜供应链管理软件 | 湖南档案密集架,智能,物证,移动,价格-湖南档案密集架厂家 | [官网]叛逆孩子管教_戒网瘾学校_全封闭问题青少年素质教育_新起点青少年特训学校 |