当前位置: 首页 > 后端技术 > Java

Ribbon工作流程详解

时间:2023-04-01 23:09:34 Java

原因是Ribbon集成了springboot和openfeign实现远程调用负载均衡。初始阶段没有添加以下配置。发现第一次远程调用,ribbon报错【readtimeout】。然后添加如下配置解决问题~#设置ribbon在项目启动时加载配置项,避免feign先调用[readtimeout]ribbon:eager-load:enabled:trueclients:api-service上面的配置字面意思是看,让Ribbon及时加载,那么问题来了?应用程序启动时功能区如何工作?好的,继续阅读!@ConfigurationProperties(prefix="ribbon.eager-load")publicclassRibbonEagerLoadProperties{privatebooleanenabled=false;privateListclients;}看吧,org.springframework.cloud.netflix.ribbon.RibbonEagerLoadProperties运行起来了。那么这个类是如何被调用的呢?@EnableConfigurationProperties({RibbonEagerLoadProperties.class,ServerIntrospectorProperties.class})@ConditionalOnProperty(value="spring.cloud.loadbalancer.ribbon.enabled",havingValue="true",matchIfMissing=true)公共类RibbonAutoConfiguration{@Autowired(required=false)privateListconfigurations=newArrayList<>();@Autowired私人RibbonEagerLoadPropertiesribbonEagerLoadProperties;@Bean@ConditionalOnProperty("ribbon.eager-load.enabled")publicRibbonApplicationContextInitializerribbonApplicationContextInitializer(){返回新的RibbonApplicationContextInitializer(springClientFactory(),ribbonEagerLoadProperties.getClients());}}这个类在spring-cloud-netflix包中,注入ribbonEagerLoadProperties,然后在ribbonApplicationContextInitializer()中声明RibbonApplicationContextInitializer类,继承了ApplicationListener,在实现方法onApplicationEvent()中调用initialize(),将我们配置的目标客户端(即“api-service”)加载到org.springframework.cloud.context.named.NamedContextFactory的context中下面是具体的调用链:图1publicvoidonApplicationEvent(ApplicationReadyEventevent){if(clientNames!=null){for(StringclientName:clientNames){this.springClientFactory.getContext(clientName);}}}protectedAnnotationConfigApplicationContextgetContext(Stringname){if(!this.contexts.containsKey(name)){synchronized(this.contexts){if(!this.contexts.containsKey(name)){//看这里和这里this.contexts.put(名字,createContext(名字));}}}返回this.contexts.get(name);}下图是NamedContextFactory中存储的AnnotationConfigApplicationContext实例:图2下面我们调用了远程服务的checkToken(),下图是响应好的具体调用栈信息:图3至此,Robbin的工作方式已经大致了解一下,更多关于Robbin的细节后续会持续更新。欢迎留言交流~可以继续探索feign执行细节org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.execute()。publicResponseexecute(Requestrequest,Request.Optionsoptions)throwsIOException{try{URIasUri=URI.create(request.url());StringclientName=asUri.getHost();URIuriWithoutHost=cleanUrl(request.url(),clientName);FeignLoadBalancer.RibbonRequestribbonRequest=newFeignLoadBalancer.RibbonRequest(this.delegate,request,uriWithoutHost);IClientConfigrequestConfig=getClientConfig(options,clientName);//这里根据clientName执行负载均衡逻辑,根据url发送n个http请求返回lbClient(clientName).executeWithLoadBalancer(ribbonRequest,requestConfig).toResponse();}catch(ClientExceptione){IOExceptionio=findIOException(e);if(io!=null){抛出io;}抛出新的RuntimeException(e);}}feign的调用链如下:其中,Client.execute()细节:publicResponseexecute(Request请求,选项options)throwsIOException{HttpURLConnectionconnection=convertAndSend(request,options);返回转换响应(连接,请求);}publicHttpURLConnectiongetConnection(finalURLurl)throwsIOException{//也在这里^_tHpurtreturn)url.openConnection();}HttpURLConnectionconvertAndSend(Requestrequest,Optionsoptions)throwsIOException{finalURLurl=newURL(request.url());//重点在这里^-^finalHttpURLConnectionconnection=this.getConnection(url);if(connectioninstanceofHttpsURLConnection){HttpsURLConnectionsslCon=(HttpsURLConnection)连接;如果(sslContextFactory!=null){sslCon.setSSLSocketFactory(sslContextFactory);}if(hostnameVerifier!=null){sslCon.setHostnameVerifier(hostname}Verif}}看到了吗,最后使用jdk的HttpURLConnection执行http请求,得到执行结果: