您好,登錄后才能下訂單哦!
這篇文章主要介紹“feign怎么獲取請求真實目的ip地址”,在日常操作中,相信很多人在feign怎么獲取請求真實目的ip地址問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”feign怎么獲取請求真實目的ip地址”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
最近小編的項目中出現了很多feign 調用出現 Read Time out 的異常,但因為沒有集成鏈路追蹤的第三方框架,查不到原因。
所以想到打印請求的ip地址,判斷是指定的服務器出現的問題還是所有服務器都有這個問題,但是feign 打印異常日志不會顯示目的端地址,這就很難受了沒辦法只能自己改裝下
需要改裝肯定需要知道feign 具體請求調用的源碼,大致需要知道下面幾個問題
feign 集成了ribbon 如何在負載均衡之后獲取真實的ip地址
feign 實際請求 http 源碼在哪
能否替換 feign http 請求的組件
之前小編有兩篇文章分析過 feign相關的源碼
自定義 feign 調用實現 hystrix 超時、異常熔斷
Feign 集成 Hystrix實現不同的調用接口不同的設置
這其中有個關鍵的源碼位置在于 InvocationHandler 的 invoke 方法,在feign 組件中大致有兩個類實現了此接口
FeignInvocationHandler HystrixInvocationHandler
如果 項目中使用了 Hystrix 那么會用到HystrixInvocationHandler那個,否則一般是FeignInvocationHandler(自定義組件的除外)
那么此時只需要在invoke 方法中打個斷點就行
此時跟蹤到
feign.SynchronousMethodHandler#executeAndDecode
Object executeAndDecode(RequestTemplate template) throws Throwable { Request request = targetRequest(template); ....... Response response; long start = System.nanoTime(); try { // 真正執行請求 response = client.execute(request, options); response.toBuilder().request(request).build(); } catch (IOException e) { .... throw errorExecuting(request, e); } ..... }
通過debug就知道這個 client 是
LoadBalancerFeignClient org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient#execute
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); // 封裝 ribbon 請求組件 FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest( this.delegate, request, uriWithoutHost); IClientConfig requestConfig = getClientConfig(options, clientName); // 這行是關鍵 return // 獲取 FeignLoadBalancer lbClient(clientName) // 負載之后請求真實的url // com.netflix.client.AbstractLoadBalancerAwareClient#executeWithLoadBalancer(....) .executeWithLoadBalancer(ribbonRequest,requestConfig) .toResponse(); } catch (ClientException e) { .... throw new RuntimeException(e); } }
com.netflix.client.AbstractLoadBalancerAwareClient#executeWithLoadBalancer(....)
public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException { LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig); try { // 在com.netflix.loadbalancer.reactive.LoadBalancerCommand#submit 中會根據 負載均衡算法之后獲取到真實的ip地址 return command.submit( new ServerOperation<T>() { @Override // 傳入的server 就是真實的ip public Observable<T> call(Server server) { URI finalUri = reconstructURIWithServer(server, request.getUri()); // 路徑替換把原本 http://client-name/xxxx 地址改為 http://127.0.0.1:9090/xxxx S requestForServer = (S) request.replaceUri(finalUri); try { // 請求父類中的 execute 方法,也就是 上面 lbClient(clientName) 返回的 FeignLoadBalancer 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); } } }
org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer#execute
@Override public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride) throws IOException { Request.Options options; ..... // 這里的 request 就是 `org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient#execute` // 封裝的FeignLoadBalancer.RibbonRequest // request.client() 返回就是 feign.Client.Default Response response = request.client().execute(request.toRequest(), options); return new RibbonResponse(request.getUri(), response); }
feign.Client.Default#execute
@Override public Response execute(Request request, Options options) throws IOException { HttpURLConnection connection = convertAndSend(request, options); return convertResponse(connection).toBuilder().request(request).build(); }
這里的request 中 url 就是真實的url資源路徑了
現在屢屢邏輯
org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient和feign.Client.Default
都實現了 feign.Client 接口,但是 LoadBalancerFeignClient 實際上調用的還是 feign.Client.Default,無非做了自己處理(負載),有些類似于靜態代理
那么上面的問題就只剩下能否替換的問題了
@Configuration class DefaultFeignLoadBalancedConfiguration { @Bean @ConditionalOnMissingBean public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory) { return new LoadBalancerFeignClient(new Client.Default(null, null), cachingFactory, clientFactory); } }
這就不需要我來過多解釋了,我們只需要自定義一個 LoadBalancerFeignClient 或者 實現Client的類就行 然后注入就行
我選擇的是 自定義實現一個 Client,去繼承 feign.Client.Default
@Slf4j public class InFeignClient extends Client.Default { /** */ public InFeignClient(SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier) { super(sslContextFactory, hostnameVerifier); } @Override public Response execute(Request request, Request.Options options) throws IOException { try { return super.execute(request, options); } catch (IOException e) { log.warn(" 請求 {} 異常 ======> {}", request.url(), e.getMessage()); throw e; } } }
然后將這個類替換
@Component public class RestConfig { public CachingSpringLoadBalancerFactory cachingLBClientFactory( SpringClientFactory factory) { return new CachingSpringLoadBalancerFactory(factory); } @Bean public Client feignClient(SpringClientFactory clientFactory) { CachingSpringLoadBalancerFactory bean = cachingLBClientFactory(clientFactory); return new LoadBalancerFeignClient(new InFeignClient(null, null), bean, clientFactory); } }
到此,關于“feign怎么獲取請求真實目的ip地址”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。