diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java index b328ede9af..19c79bdcf2 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java @@ -68,13 +68,16 @@ public boolean retryRequest(IOException exception, int executionCount, HttpConte * 闲置连接监控线程 */ private IdleConnectionMonitorThread idleConnectionMonitorThread; - private HttpClientBuilder httpClientBuilder; + /** + * 持有client对象,仅初始化一次,避免多service实例的时候造成重复初始化的问题 + */ + private CloseableHttpClient closeableHttpClient; private DefaultApacheHttpClientBuilder() { } public static DefaultApacheHttpClientBuilder get() { - return new DefaultApacheHttpClientBuilder(); + return DefaultApacheHttpClientBuilder.SingletonHolder.INSTANCE; } @Override @@ -219,7 +222,7 @@ private synchronized void prepare() { this.idleConnectionMonitorThread.setDaemon(true); this.idleConnectionMonitorThread.start(); - this.httpClientBuilder = HttpClients.custom() + HttpClientBuilder httpClientBuilder = HttpClients.custom() .setConnectionManager(connectionManager) .setConnectionManagerShared(true) .setSSLSocketFactory(this.buildSSLConnectionSocketFactory()) @@ -240,12 +243,13 @@ private synchronized void prepare() { new AuthScope(this.httpProxyHost, this.httpProxyPort), new UsernamePasswordCredentials(this.httpProxyUsername, this.httpProxyPassword)); - this.httpClientBuilder.setDefaultCredentialsProvider(provider); + httpClientBuilder.setDefaultCredentialsProvider(provider); } if (StringUtils.isNotBlank(this.userAgent)) { - this.httpClientBuilder.setUserAgent(this.userAgent); + httpClientBuilder.setUserAgent(this.userAgent); } + this.closeableHttpClient = httpClientBuilder.build(); prepared.set(true); } @@ -277,7 +281,14 @@ public CloseableHttpClient build() { if (!prepared.get()) { prepare(); } - return this.httpClientBuilder.build(); + return this.closeableHttpClient; + } + + /** + * DefaultApacheHttpClientBuilder 改为单例模式,并持有唯一的CloseableHttpClient(仅首次调用创建) + */ + private static class SingletonHolder { + private static final DefaultApacheHttpClientBuilder INSTANCE = new DefaultApacheHttpClientBuilder(); } public static class IdleConnectionMonitorThread extends Thread { diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilderTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilderTest.java new file mode 100644 index 0000000000..24a45eea09 --- /dev/null +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilderTest.java @@ -0,0 +1,64 @@ +package me.chanjar.weixin.common.util.http.apache; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class DefaultApacheHttpClientBuilderTest { + @Test + public void testBuild() throws Exception { + DefaultApacheHttpClientBuilder builder1 = DefaultApacheHttpClientBuilder.get(); + DefaultApacheHttpClientBuilder builder2 = DefaultApacheHttpClientBuilder.get(); + Assert.assertSame(builder1, builder2, "DefaultApacheHttpClientBuilder为单例,获取到的对象应该相同"); + List threadList = new ArrayList<>(10); + for (int i = 0; i < 10; i++) { + TestThread thread = new TestThread(); + thread.start(); + threadList.add(thread); + } + for (TestThread testThread : threadList) { + testThread.join(); + Assert.assertNotEquals(-1,testThread.getRespState(),"请求响应code不应为-1"); + } + + for (int i = 1; i < threadList.size(); i++) { + TestThread thread1 = threadList.get(i - 1); + TestThread thread2 = threadList.get(i); + Assert.assertSame( + thread1.getClient(), + thread2.getClient(), + "DefaultApacheHttpClientBuilder为单例,并持有了相同的HttpClient" + ); + } + } + + + public static class TestThread extends Thread { + private CloseableHttpClient client; + private int respState = -1; + + @Override + public void run() { + client = DefaultApacheHttpClientBuilder.get().build(); + HttpGet httpGet = new HttpGet("http://www.sina.com.cn/"); + try (CloseableHttpResponse resp = client.execute(httpGet)){ + respState = resp.getStatusLine().getStatusCode(); + } catch (IOException ignored) { + } + } + + public CloseableHttpClient getClient() { + return client; + } + + public int getRespState() { + return respState; + } + } +}