欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringCloud?Feign使用ApacheHttpClient代替默認(rèn)client方式

 更新時(shí)間:2022年03月09日 10:01:00   作者:過河的小卒子  
這篇文章主要介紹了SpringCloud?Feign使用ApacheHttpClient代替默認(rèn)client方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

使用ApacheHttpClient代替默認(rèn)client

ApacheHttpClient和默認(rèn)實(shí)現(xiàn)的比較

  • Feign在默認(rèn)情況下使用的是JDK原生的URLConnection發(fā)送HTTP請求,沒有連接池,但是對每個(gè)地址會(huì)保持一個(gè)長連接,即利用HTTP的persistence connection。
  • ApacheHttpClient實(shí)現(xiàn)了連接池,同時(shí)它封裝了訪問http的請求頭,參數(shù),內(nèi)容體,響應(yīng)等等,使客戶端發(fā)送 HTTP 請求變得容易。

ApacheHttpClient 使用

maven 依賴

? ? <dependency>
? ? ? ? <groupId>org.springframework.cloud</groupId>
? ? ? ? <artifactId>spring-cloud-starter-openfeign</artifactId>
? ? </dependency>
? ? <dependency>
? ? ? ? <groupId>org.apache.httpcomponents</groupId>
? ? ? ? <artifactId>httpclient</artifactId>
? ? ? ? <version>4.5.7</version>
? ? </dependency>
? ? <dependency>
? ? ? ? <groupId>io.github.openfeign</groupId>
? ? ? ? <artifactId>feign-httpclient</artifactId>
? ? ? ? <version>10.1.0</version>
? ? </dependency>

配置文件的修改

feign:
? httpclient:
? ? enabled: true

創(chuàng)建ApacheHttpClient客戶端

import javax.net.ssl.SSLContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.springframework.util.ResourceUtils;
import feign.httpclient.ApacheHttpClient;
@Slf4j
public class FeignClientBuilder {
? private boolean enabled;
? private String keyPassword;
? private String keyStore;
? private String keyStorePassword;
? private String trustStore;
? private String trustStorePassword;
? private int maxConnTotal = 2048;
? private int maxConnPerRoute = 512;
? public FeignClientBuilder(boolean enabled, String keyPassword, String keyStore, String keyStorePassword, String trustStore, String trustStorePassword, int maxConnTotal, int maxConnPerRoute) {
? ? this.enabled = enabled;
? ? this.keyPassword = keyPassword;
? ? this.keyStore = keyStore;
? ? this.keyStorePassword = keyStorePassword;
? ? this.trustStore = trustStore;
? ? this.trustStorePassword = trustStorePassword;
? ? /**
? ? ?* maxConnTotal是同時(shí)間正在使用的最多的連接數(shù)
? ? ?*/
? ? this.maxConnTotal = maxConnTotal;
? ? /**
? ? ?* maxConnPerRoute是針對一個(gè)域名同時(shí)間正在使用的最多的連接數(shù)
? ? ?*/
? ? this.maxConnPerRoute = maxConnPerRoute;
? }
? public ApacheHttpClient apacheHttpClient() {
? ? CloseableHttpClient defaultHttpClient = HttpClients.custom()
? ? ? ? ? ? .setMaxConnTotal(maxConnTotal)
? ? ? ? ? ? .setMaxConnPerRoute(maxConnPerRoute)
? ? ? ? ? ? .build();
? ? ApacheHttpClient defaultApacheHttpClient = new ApacheHttpClient(defaultHttpClient);
? ? if (!enabled) {
? ? ? return defaultApacheHttpClient;
? ? }
? ? SSLContextBuilder sslContextBuilder = SSLContexts.custom();
? ? // 如果 服務(wù)端啟用了 TLS 客戶端驗(yàn)證,則需要指定 keyStore
? ? if (keyStore == null || keyStore.isEmpty()) {
? ? ? return new ApacheHttpClient();
? ? } else {
? ? ? try {
? ? ? ? sslContextBuilder
? ? ? ? ? ? ? ? .loadKeyMaterial(
? ? ? ? ? ? ? ? ? ? ? ? ResourceUtils.getFile(keyStore),
? ? ? ? ? ? ? ? ? ? ? ? keyStorePassword.toCharArray(),
? ? ? ? ? ? ? ? ? ? ? ? keyPassword.toCharArray());
? ? ? } catch (Exception e) {
? ? ? ? e.printStackTrace();
? ? ? }
? ? }
? ? // 如果 https 使用自簽名證書,則需要指定 trustStore
? ? if (trustStore == null || trustStore.isEmpty()) {
? ? } else {
? ? ? try {
? ? ? ? sslContextBuilder
// ? ? ? ?.loadTrustMaterial(TrustAllStrategy.INSTANCE)
? ? ? ? ? ? ? ? .loadTrustMaterial(
? ? ? ? ? ? ? ? ? ? ? ? ResourceUtils.getFile(trustStore),
? ? ? ? ? ? ? ? ? ? ? ? trustStorePassword.toCharArray()
? ? ? ? ? ? ? ? );
? ? ? } catch (Exception e) {
? ? ? ? e.printStackTrace();
? ? ? }
? ? }
? ? try {
? ? ? SSLContext sslContext = sslContextBuilder.build();
? ? ? SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
? ? ? ? ? ? ? sslContext,
? ? ? ? ? ? ? SSLConnectionSocketFactory.getDefaultHostnameVerifier());
? ? ? CloseableHttpClient httpClient = HttpClients.custom()
? ? ? ? ? ? ? .setMaxConnTotal(maxConnTotal)
? ? ? ? ? ? ? .setMaxConnPerRoute(maxConnPerRoute)
? ? ? ? ? ? ? .setSSLSocketFactory(sslsf)
? ? ? ? ? ? ? .build();
? ? ? ApacheHttpClient apacheHttpClient = new ApacheHttpClient(httpClient);
? ? ? log.info("feign Client load with ssl.");
? ? ? return apacheHttpClient;
? ? } catch (Exception e) {
? ? ? e.printStackTrace();
? ? }
? ? return defaultApacheHttpClient;
? }
? public static FeignClientBuilderBuilder builder() {
? ? return new FeignClientBuilderBuilder();
? }
? public static class FeignClientBuilderBuilder {
? ? private boolean enabled;
? ? private String keyPassword;
? ? private String keyStore;
? ? private String keyStorePassword;
? ? private String trustStore;
? ? private String trustStorePassword;
? ? private int maxConnTotal = 2048;
? ? private int maxConnPerRoute = 512;
? ? public FeignClientBuilderBuilder enabled(boolean enabled) {
? ? ? this.enabled = enabled;
? ? ? return this;
? ? }
? ? public FeignClientBuilderBuilder keyPassword(String keyPassword) {
? ? ? this.keyPassword = keyPassword;
? ? ? return this;
? ? }
? ? public FeignClientBuilderBuilder keyStore(String keyStore) {
? ? ? this.keyStore = keyStore;
? ? ? return this;
? ? }
? ? public FeignClientBuilderBuilder keyStorePassword(String keyStorePassword) {
? ? ? this.keyStorePassword = keyStorePassword;
? ? ? return this;
? ? }
? ? public FeignClientBuilderBuilder trustStore(String trustStore) {
? ? ? this.trustStore = trustStore;
? ? ? return this;
? ? }
? ? public FeignClientBuilderBuilder trustStorePassword(String trustStorePassword) {
? ? ? this.trustStorePassword = trustStorePassword;
? ? ? return this;
? ? }
? ? public FeignClientBuilderBuilder maxConnTotal(int maxConnTotal) {
? ? ? this.maxConnTotal = maxConnTotal;
? ? ? return this;
? ? }
? ? public FeignClientBuilderBuilder maxConnPerRoute(int maxConnPerRoute) {
? ? ? this.maxConnPerRoute = maxConnPerRoute;
? ? ? return this;
? ? }
? ? public FeignClientBuilder build() {
? ? ? return new FeignClientBuilder(
? ? ? ? ? ? ? this.enabled,
? ? ? ? ? ? ? this.keyPassword,
? ? ? ? ? ? ? this.keyStore,
? ? ? ? ? ? ? this.keyStorePassword,
? ? ? ? ? ? ? this.trustStore,
? ? ? ? ? ? ? this.trustStorePassword,
? ? ? ? ? ? ? this.maxConnTotal,
? ? ? ? ? ? ? this.maxConnPerRoute
? ? ? );
? ? }
? }
}

使用時(shí)可以直接使用builder來創(chuàng)建ApacheHttpClient。

apache的HttpClient默認(rèn)重試機(jī)制

maven

? ? ? ? <dependency>
? ? ? ? ? ? <groupId>org.apache.httpcomponents</groupId>
? ? ? ? ? ? <artifactId>httpclient</artifactId>
? ? ? ? ? ? <version>4.5.2</version>
? ? ? ? </dependency>

異常重試log

2017-01-31 19:31:39.057  INFO 3873 --- [askScheduler-13] o.apache.http.impl.execchain.RetryExec   : I/O exception (org.apache.http.NoHttpResponseException) caught when processing request to {}->http://192.168.99.100:8080: The target server failed to respond
2017-01-31 19:31:39.058  INFO 3873 --- [askScheduler-13] o.apache.http.impl.execchain.RetryExec   : Retrying request to {}->http://192.168.99.100:8080

RetryExec

org/apache/http/impl/execchain/RetryExec.java

/**
?* Request executor in the request execution chain that is responsible
?* for making a decision whether a request failed due to an I/O error
?* should be re-executed.
?* <p>
?* Further responsibilities such as communication with the opposite
?* endpoint is delegated to the next executor in the request execution
?* chain.
?* </p>
?*
?* @since 4.3
?*/
@Immutable
public class RetryExec implements ClientExecChain {
? ? private final Log log = LogFactory.getLog(getClass());
? ? private final ClientExecChain requestExecutor;
? ? private final HttpRequestRetryHandler retryHandler;
? ? public RetryExec(
? ? ? ? ? ? final ClientExecChain requestExecutor,
? ? ? ? ? ? final HttpRequestRetryHandler retryHandler) {
? ? ? ? Args.notNull(requestExecutor, "HTTP request executor");
? ? ? ? Args.notNull(retryHandler, "HTTP request retry handler");
? ? ? ? this.requestExecutor = requestExecutor;
? ? ? ? this.retryHandler = retryHandler;
? ? }
? ? @Override
? ? public CloseableHttpResponse execute(
? ? ? ? ? ? final HttpRoute route,
? ? ? ? ? ? final HttpRequestWrapper request,
? ? ? ? ? ? final HttpClientContext context,
? ? ? ? ? ? final HttpExecutionAware execAware) throws IOException, HttpException {
? ? ? ? Args.notNull(route, "HTTP route");
? ? ? ? Args.notNull(request, "HTTP request");
? ? ? ? Args.notNull(context, "HTTP context");
? ? ? ? final Header[] origheaders = request.getAllHeaders();
? ? ? ? for (int execCount = 1;; execCount++) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? return this.requestExecutor.execute(route, request, context, execAware);
? ? ? ? ? ? } catch (final IOException ex) {
? ? ? ? ? ? ? ? if (execAware != null && execAware.isAborted()) {
? ? ? ? ? ? ? ? ? ? this.log.debug("Request has been aborted");
? ? ? ? ? ? ? ? ? ? throw ex;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (retryHandler.retryRequest(ex, execCount, context)) {
? ? ? ? ? ? ? ? ? ? if (this.log.isInfoEnabled()) {
? ? ? ? ? ? ? ? ? ? ? ? this.log.info("I/O exception ("+ ex.getClass().getName() +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ") caught when processing request to "
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? + route +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ": "
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? + ex.getMessage());
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? if (this.log.isDebugEnabled()) {
? ? ? ? ? ? ? ? ? ? ? ? this.log.debug(ex.getMessage(), ex);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? if (!RequestEntityProxy.isRepeatable(request)) {
? ? ? ? ? ? ? ? ? ? ? ? this.log.debug("Cannot retry non-repeatable request");
? ? ? ? ? ? ? ? ? ? ? ? throw new NonRepeatableRequestException("Cannot retry request " +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "with a non-repeatable request entity", ex);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? request.setHeaders(origheaders);
? ? ? ? ? ? ? ? ? ? if (this.log.isInfoEnabled()) {
? ? ? ? ? ? ? ? ? ? ? ? this.log.info("Retrying request to " + route);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? if (ex instanceof NoHttpResponseException) {
? ? ? ? ? ? ? ? ? ? ? ? final NoHttpResponseException updatedex = new NoHttpResponseException(
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? route.getTargetHost().toHostString() + " failed to respond");
? ? ? ? ? ? ? ? ? ? ? ? updatedex.setStackTrace(ex.getStackTrace());
? ? ? ? ? ? ? ? ? ? ? ? throw updatedex;
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? throw ex;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
}

DefaultHttpRequestRetryHandler

org/apache/http/impl/client/DefaultHttpRequestRetryHandler.java

/**
?* The default {@link HttpRequestRetryHandler} used by request executors.
?*
?* @since 4.0
?*/
@Immutable
public class DefaultHttpRequestRetryHandler implements HttpRequestRetryHandler {
? ? public static final DefaultHttpRequestRetryHandler INSTANCE = new DefaultHttpRequestRetryHandler();
? ? /** the number of times a method will be retried */
? ? private final int retryCount;
? ? /** Whether or not methods that have successfully sent their request will be retried */
? ? private final boolean requestSentRetryEnabled;
? ? private final Set<Class<? extends IOException>> nonRetriableClasses;
? ? /**
? ? ?* Create the request retry handler using the specified IOException classes
? ? ?*
? ? ?* @param retryCount how many times to retry; 0 means no retries
? ? ?* @param requestSentRetryEnabled true if it's OK to retry requests that have been sent
? ? ?* @param clazzes the IOException types that should not be retried
? ? ?* @since 4.3
? ? ?*/
? ? protected DefaultHttpRequestRetryHandler(
? ? ? ? ? ? final int retryCount,
? ? ? ? ? ? final boolean requestSentRetryEnabled,
? ? ? ? ? ? final Collection<Class<? extends IOException>> clazzes) {
? ? ? ? super();
? ? ? ? this.retryCount = retryCount;
? ? ? ? this.requestSentRetryEnabled = requestSentRetryEnabled;
? ? ? ? this.nonRetriableClasses = new HashSet<Class<? extends IOException>>();
? ? ? ? for (final Class<? extends IOException> clazz: clazzes) {
? ? ? ? ? ? this.nonRetriableClasses.add(clazz);
? ? ? ? }
? ? }
? ? /**
? ? ?* Create the request retry handler using the following list of
? ? ?* non-retriable IOException classes: <br>
? ? ?* <ul>
? ? ?* <li>InterruptedIOException</li>
? ? ?* <li>UnknownHostException</li>
? ? ?* <li>ConnectException</li>
? ? ?* <li>SSLException</li>
? ? ?* </ul>
? ? ?* @param retryCount how many times to retry; 0 means no retries
? ? ?* @param requestSentRetryEnabled true if it's OK to retry non-idempotent requests that have been sent
? ? ?*/
? ? @SuppressWarnings("unchecked")
? ? public DefaultHttpRequestRetryHandler(final int retryCount, final boolean requestSentRetryEnabled) {
? ? ? ? this(retryCount, requestSentRetryEnabled, Arrays.asList(
? ? ? ? ? ? ? ? InterruptedIOException.class,
? ? ? ? ? ? ? ? UnknownHostException.class,
? ? ? ? ? ? ? ? ConnectException.class,
? ? ? ? ? ? ? ? SSLException.class));
? ? }
? ? /**
? ? ?* Create the request retry handler with a retry count of 3, requestSentRetryEnabled false
? ? ?* and using the following list of non-retriable IOException classes: <br>
? ? ?* <ul>
? ? ?* <li>InterruptedIOException</li>
? ? ?* <li>UnknownHostException</li>
? ? ?* <li>ConnectException</li>
? ? ?* <li>SSLException</li>
? ? ?* </ul>
? ? ?*/
? ? public DefaultHttpRequestRetryHandler() {
? ? ? ? this(3, false);
? ? }
? ? /**
? ? ?* Used {@code retryCount} and {@code requestSentRetryEnabled} to determine
? ? ?* if the given method should be retried.
? ? ?*/
? ? @Override
? ? public boolean retryRequest(
? ? ? ? ? ? final IOException exception,
? ? ? ? ? ? final int executionCount,
? ? ? ? ? ? final HttpContext context) {
? ? ? ? Args.notNull(exception, "Exception parameter");
? ? ? ? Args.notNull(context, "HTTP context");
? ? ? ? if (executionCount > this.retryCount) {
? ? ? ? ? ? // Do not retry if over max retry count
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? if (this.nonRetriableClasses.contains(exception.getClass())) {
? ? ? ? ? ? return false;
? ? ? ? } else {
? ? ? ? ? ? for (final Class<? extends IOException> rejectException : this.nonRetriableClasses) {
? ? ? ? ? ? ? ? if (rejectException.isInstance(exception)) {
? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? final HttpClientContext clientContext = HttpClientContext.adapt(context);
? ? ? ? final HttpRequest request = clientContext.getRequest();
? ? ? ? if(requestIsAborted(request)){
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? if (handleAsIdempotent(request)) {
? ? ? ? ? ? // Retry if the request is considered idempotent
? ? ? ? ? ? return true;
? ? ? ? }
? ? ? ? if (!clientContext.isRequestSent() || this.requestSentRetryEnabled) {
? ? ? ? ? ? // Retry if the request has not been sent fully or
? ? ? ? ? ? // if it's OK to retry methods that have been sent
? ? ? ? ? ? return true;
? ? ? ? }
? ? ? ? // otherwise do not retry
? ? ? ? return false;
? ? }
? ? /**
? ? ?* @return {@code true} if this handler will retry methods that have
? ? ?* successfully sent their request, {@code false} otherwise
? ? ?*/
? ? public boolean isRequestSentRetryEnabled() {
? ? ? ? return requestSentRetryEnabled;
? ? }
? ? /**
? ? ?* @return the maximum number of times a method will be retried
? ? ?*/
? ? public int getRetryCount() {
? ? ? ? return retryCount;
? ? }
? ? /**
? ? ?* @since 4.2
? ? ?*/
? ? protected boolean handleAsIdempotent(final HttpRequest request) {
? ? ? ? return !(request instanceof HttpEntityEnclosingRequest);
? ? }
? ? /**
? ? ?* @since 4.2
? ? ?*
? ? ?* @deprecated (4.3)
? ? ?*/
? ? @Deprecated
? ? protected boolean requestIsAborted(final HttpRequest request) {
? ? ? ? HttpRequest req = request;
? ? ? ? if (request instanceof RequestWrapper) { // does not forward request to original
? ? ? ? ? ? req = ((RequestWrapper) request).getOriginal();
? ? ? ? }
? ? ? ? return (req instanceof HttpUriRequest && ((HttpUriRequest)req).isAborted());
? ? }
}

默認(rèn)重試3次,三次都失敗則拋出NoHttpResponseException或其他異常

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 使用IntelliJ IDEA 進(jìn)行代碼對比的方法(兩種方法)

    使用IntelliJ IDEA 進(jìn)行代碼對比的方法(兩種方法)

    這篇文章給大家?guī)砹藘煞NIntelliJ IDEA 進(jìn)行代碼對比的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • IDEA新建的Moudle失效顯示為灰色的完美解決方案

    IDEA新建的Moudle失效顯示為灰色的完美解決方案

    這篇文章主要介紹了IDEA新建的Moudle失效顯示為灰色,本文通過圖文并茂的形式給大家分享完美解決方案,需要的朋友可以參考下
    2023-09-09
  • Java8處理List的雙層循環(huán)問題

    Java8處理List的雙層循環(huán)問題

    這篇文章主要介紹了Java8處理List的雙層循環(huán)問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • springboot多文件上傳實(shí)現(xiàn)使用postman測試多文件上傳接口

    springboot多文件上傳實(shí)現(xiàn)使用postman測試多文件上傳接口

    這篇文章主要介紹了springboot多文件上傳實(shí)現(xiàn)使用postman測試多文件上傳接口,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • springBoot加入thymeleaf模板的方式

    springBoot加入thymeleaf模板的方式

    這篇文章主要介紹了springBoot加入thymeleaf模板的方式,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • MyBatis中的limit分頁設(shè)置

    MyBatis中的limit分頁設(shè)置

    這篇文章主要介紹了MyBatis中的limit分頁設(shè)置方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • SpringBoot中使用Swagger的超簡單方法

    SpringBoot中使用Swagger的超簡單方法

    大家一致認(rèn)為springBoot使用swagger太麻煩了,每次都需要編寫config,今天小編告訴大家一種超簡單配置方法,教大家如何整合swagger,感興趣的朋友跟隨小編一起看看吧
    2021-07-07
  • 帶你快速搞定java多線程

    帶你快速搞定java多線程

    這篇文章主要介紹了java多線程編程實(shí)例,分享了幾則多線程的實(shí)例代碼,具有一定參考價(jià)值,加深多線程編程的理解還是很有幫助的,需要的朋友可以參考下
    2021-07-07
  • java?Spring的啟動(dòng)原理詳解

    java?Spring的啟動(dòng)原理詳解

    大家好,本篇文章主要講的是java?Spring的啟動(dòng)原理詳解,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • springboot tomcat最大線程數(shù)與最大連接數(shù)解析

    springboot tomcat最大線程數(shù)與最大連接數(shù)解析

    這篇文章主要介紹了springboot tomcat最大線程數(shù)與最大連接數(shù)解析,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06

最新評論