最近公司android項目處於維護階段,開始做了一些java和運維的項目,也用nexus搭建公司的私服,好了,廢話也不多說,開始今天的主題,怎麼用HttpClient的請求框架綁定本地發送請求端口
我們都知道,網路簡歷連接,都離不開socket套接字,所以只有在這裏我們才能設置好網路請求一些參數
寫了一個小程序,試了一下綁定socket的本地端口
public void send(String ip,int port,String url,String sendData)
{
try {
Socket socket = new Socket(ip, port,InetAddress.getByName("192.168.100.165"),10011);
OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());
StringBuffer sb = new StringBuffer();
//http協議中請求行
sb.append("GET "+url+" HTTP/1.1\r\n");
//http協議中請求頭
sb.append("Host: "+ip+"\r\n");
sb.append("Connection: Keep-Alive\r\n");
sb.append("user-agent: 1601\r\n");
sb.append("\r\n");
osw.write(sb.toString());
osw.flush();
//傳回的消息的頭信息
InputStream is = socket.getInputStream();
String line = null;
int contentLength = 0;
// 服務器發送過來的請求參數頭部信息
do {
line = readLine(is, 0);
//如果有Content-Length消息頭時取出
if (line.startsWith("Content-Length")) {
contentLength = Integer.parseInt(line.split(":")[1].trim());
}
//打印請求部信息
System.out.print(line);
//單獨的回車換行,則表示請求頭結束
} while (!line.equals("\r\n"));
System.out.print(readLine(is, contentLength));
is.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String readLine(InputStream is, int contentLe) throws IOException {
ArrayList lineByteList = new ArrayList();
byte readByte;
int total = 0;
if (contentLe != 0) {
do {
readByte = (byte) is.read();
lineByteList.add(Byte.valueOf(readByte));
total++;
} while (total < contentLe);//消息體讀還未讀完
} else {
do {
readByte = (byte) is.read();
lineByteList.add(Byte.valueOf(readByte));
} while (readByte != 10);
}
byte[] tmpByteArr = new byte[lineByteList.size()];
for (int i = 0; i < lineByteList.size(); i++) {
tmpByteArr[i] = ((Byte) lineByteList.get(i)).byteValue();
}
lineByteList.clear();
return new String(tmpByteArr, encoding);
}
public static void main(String[] args) {
SimpleHttpClient httpClient=new SimpleHttpClient();
httpClient.send("61.135.169.121",
443, "/index.php?tn=monline_3_dg",
null);
}
請求的是百度的地址,我們抓包看看,端口是真的綁定了
這裏可以看到,發送的資源端口爲10011,與上面綁定的恩地端口10011是一樣的,爲了防止是巧合,我們再請求兩次
可以看到,端口確實是綁定了。
接下來,就是正式用到項目裏面了
首先,我們來看一下公司直接的rest請求工具類RestTemplateUtil
@Component
public class RestTemplateUtil {
private RestTemplate restTemplate;
private RestTemplate httpsRestTemplate;
private int timeout = 5000;
private String APPLICATION_JSON_UTF8 = "application/json;charset=UTF-8";
private String APPLICATION_XML_UTF8 = "application/xml;charset=UTF-8";
public RestTemplateUtil() {
restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setReadTimeout(timeout);
requestFactory.setConnectTimeout(timeout);
restTemplate.setRequestFactory(requestFactory);
httpsRestTemplate = new RestTemplate();
SimpleClientHttpRequestFactory requestFactoryHttps = new HttpsClientRequestFactory();
requestFactoryHttps.setReadTimeout(timeout);
requestFactoryHttps.setConnectTimeout(timeout);
httpsRestTemplate.setRequestFactory(requestFactoryHttps);
}
private <T> T post(String url, String param, String mediaType, Class<T> bodyType) {
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType(mediaType);
headers.setContentType(type);
return exchange(url, param, HttpMethod.POST, bodyType, headers);
}
public <T> T postJson(String url, String param, Class<T> bodyType) {
return post(url, param, APPLICATION_JSON_UTF8, bodyType);
}
public <T> T postXml(String url, String param, Class<T> bodyType) {
return post(url, param, APPLICATION_XML_UTF8, bodyType);
}
public <T> T get(String url, String param, Class<T> bodyType) {
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType(APPLICATION_JSON_UTF8);
headers.setContentType(type);
return exchange(url, param, HttpMethod.GET, bodyType, headers);
}
public <T> T put(String url, String data, Class<T> bodyType) {
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType(APPLICATION_JSON_UTF8);
headers.setContentType(type);
return exchange(url, data, HttpMethod.PUT, bodyType, headers);
}
public <T> T delete(String url, String data, Class<T> bodyType) {
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType(APPLICATION_JSON_UTF8);
headers.setContentType(type);
return exchange(url, data, HttpMethod.DELETE, bodyType, headers);
}
/**
* 發送/獲取 服務端數據(主要用於解決發送put,delete方法無返回值問題)
*
* @param url
* @param content
* @param method
* @param bodyType
* @param headers
* @param <T>
* @return
*/
private <T> T exchange(String url, String content, HttpMethod method, Class<T> bodyType, HttpHeaders headers) {
// 發送請求
HttpEntity<String> entity = new HttpEntity<>(content, headers);
ResponseEntity<T> resultEntity = restTemplate.exchange(url, method, entity, bodyType);
return resultEntity.getBody();
}
public <T> T convertToBean(Class<T> clz, String msg) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(clz);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
T t = (T) unmarshaller.unmarshal(new StringReader(msg));
return t;
} catch (JAXBException e) {
e.printStackTrace();
}
return null;
}
public String convertToXml(Object bean) {
try {
JAXBContext context = JAXBContext.newInstance(bean.getClass());
Marshaller marshaller = context.createMarshaller();
StringWriter writer = new StringWriter();
marshaller.marshal(bean, writer);
return writer.toString();
} catch (JAXBException e) {
e.printStackTrace();
}
return null;
}
public <T> T httpsGet(String url, String param, Class<T> bodyType) {
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType(APPLICATION_JSON_UTF8);
headers.setContentType(type);
return exchangeHttps(url, param, HttpMethod.GET, bodyType, headers);
}
public <T> T httpsPost(String url, String param, Class<T> bodyType) {
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType(APPLICATION_JSON_UTF8);
headers.setContentType(type);
return exchangeHttps(url,param,HttpMethod.POST,bodyType,headers);
}
private <T> T exchangeHttps(String url, String content, HttpMethod method, Class<T> bodyType, HttpHeaders headers) {
// 發送請求
HttpEntity<String> entity = new HttpEntity<>(content, headers);
ResponseEntity<T> resultEntity = httpsRestTemplate.exchange(url, method, entity, bodyType);
return resultEntity.getBody();
}
}
可以看到,主要請求的配置還是在構造方法這裏
public RestTemplateUtil() {
restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setReadTimeout(timeout);
requestFactory.setConnectTimeout(timeout);
restTemplate.setRequestFactory(requestFactory);
httpsRestTemplate = new RestTemplate();
SimpleClientHttpRequestFactory requestFactoryHttps = new HttpsClientRequestFactory();
requestFactoryHttps.setReadTimeout(timeout);
requestFactoryHttps.setConnectTimeout(timeout);
httpsRestTemplate.setRequestFactory(requestFactoryHttps);
}
這裏新建了兩個ResTemplate對象,一個是用於http請求,一個則是用於https請求
主要注意這兩個地方,一個是http請求的請求工廠類SimpleClientHttpRequestFactory,還有一個則是https請求工廠類HttpsClientRequestFactory,可以看出來https請求工廠類是繼承SimpleClientHttpRequestFactory的,這裏spring框架中的restemplate類,在初始化的時候都需要傳入一個請求工廠來管理請求,那我們要控制端口,就只能從這個請求工廠類着手了
看一下傳入的工廠是個什麼東西
/**
* Set the request factory that this accessor uses for obtaining client request handles.
* <p>The default is a {@link SimpleClientHttpRequestFactory} based on the JDK's own
* HTTP libraries ({@link java.net.HttpURLConnection}).
* <p><b>Note that the standard JDK HTTP library does not support the HTTP PATCH method.
* Configure the Apache HttpComponents or OkHttp request factory to enable PATCH.</b>
* @see #createRequest(URI, HttpMethod)
* @see org.springframework.http.client.HttpComponentsAsyncClientHttpRequestFactory
* @see org.springframework.http.client.OkHttp3ClientHttpRequestFactory
*/
public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
Assert.notNull(requestFactory, "ClientHttpRequestFactory must not be null");
this.requestFactory = requestFactory;
}
點進方法,可以打看到傳入的ClientHttpRequestFactory一個類,這是個接口,再看一下他的實現
可以看到,所有的實現類都必須實現
ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;
這個接口,用來創建請求
在實現類裏面:
SimpleClientHttpRequestFactory,請求是用是的java自帶的網絡請求框架,而且它也只有一個集成類,就是那個https請求的工廠類HttpsClientRequestFactory
@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
prepareConnection(connection, httpMethod.name());
if (this.bufferRequestBody) {
return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming);
}
else {
return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);
}
}
我們看這個方法裏面,創建的HttpURConnection對象,就是java.net包下的,好了,這個不是重點
裏面我們還可以看到有okhttp和okhttp3的工廠類,這些都是用okhttp的網絡請求框架來來實現的rest請求,因爲沒有導okhttp的包,所以源碼進去會報錯,時間原因,我也沒有深究這個了
接下來,重點來了
HttpComponentsClientHttpRequestFactory請求工廠,使用的是HttpClient網絡請求框架
注意這需要自己添加HttpClient相關的依賴包,我用的是這個
compile group: 'org.apache.httpcomponents', name: 'httpcore', version: '4.4.1'
compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.1'
看看這個類
/**
* Create a new instance of the {@code HttpComponentsClientHttpRequestFactory}
* with a default {@link HttpClient}.
*/
public HttpComponentsClientHttpRequestFactory() {
this.httpClient = HttpClients.createSystem();
}
/**
* Create a new instance of the {@code HttpComponentsClientHttpRequestFactory}
* with the given {@link HttpClient} instance.
* @param httpClient the HttpClient instance to use for this request factory
*/
public HttpComponentsClientHttpRequestFactory(HttpClient httpClient) {
setHttpClient(httpClient);
}
可以看到構造函數有兩個,一個無參構造,另一個是有參,可以傳入一個HttpClient的對象,既然要自定義,那肯定是選擇第二個構造來創建這個對象咯
接下來就是這麼寫這個HttpClient實例了
public interface HttpClient {
看,這是個接口,看看無參是這麼創建的實例
this.httpClient = HttpClients.createSystem();
用的是一個HttpCliens類來創建的實例對象,再去看看HttpClients
@Immutable
public class HttpClients {
private HttpClients() {
super();
}
/**
* Creates builder object for construction of custom
* {@link CloseableHttpClient} instances.
*/
public static HttpClientBuilder custom() {
return HttpClientBuilder.create();
}
/**
* Creates {@link CloseableHttpClient} instance with default
* configuration.
*/
public static CloseableHttpClient createDefault() {
return HttpClientBuilder.create().build();
}
/**
* Creates {@link CloseableHttpClient} instance with default
* configuration based on ssytem properties.
*/
public static CloseableHttpClient createSystem() {
return HttpClientBuilder.create().useSystemProperties().build();
}
/**
* Creates {@link CloseableHttpClient} instance that implements
* the most basic HTTP protocol support.
*/
public static CloseableHttpClient createMinimal() {
return new MinimalHttpClient(new PoolingHttpClientConnectionManager());
}
/**
* Creates {@link CloseableHttpClient} instance that implements
* the most basic HTTP protocol support.
*/
public static CloseableHttpClient createMinimal(final HttpClientConnectionManager connManager) {
return new MinimalHttpClient(connManager);
}
}
可以看到,調用的是HttpClientBuilder的類創建實例,useSystemProperties()方法只是設置一個配置參數
/**
* Use system properties when creating and configuring default
* implementations.
*/
public final HttpClientBuilder useSystemProperties() {
this.systemProperties = true;
return this;
}
是否爲系統配置參數,在創建實例的時候會用到,主要是build()方法,我們進去看看
public CloseableHttpClient build() {
// Create main request executor
// We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version
PublicSuffixMatcher publicSuffixMatcherCopy = this.publicSuffixMatcher;
if (publicSuffixMatcherCopy == null) {
publicSuffixMatcherCopy = PublicSuffixMatcherLoader.getDefault();
}
HttpRequestExecutor requestExecCopy = this.requestExec;
if (requestExecCopy == null) {
requestExecCopy = new HttpRequestExecutor();
}
HttpClientConnectionManager connManagerCopy = this.connManager;
if (connManagerCopy == null) {
LayeredConnectionSocketFactory sslSocketFactoryCopy = this.sslSocketFactory;
if (sslSocketFactoryCopy == null) {
final String[] supportedProtocols = systemProperties ? split(
System.getProperty("https.protocols")) : null;
final String[] supportedCipherSuites = systemProperties ? split(
System.getProperty("https.cipherSuites")) : null;
HostnameVerifier hostnameVerifierCopy = this.hostnameVerifier;
if (hostnameVerifierCopy == null) {
hostnameVerifierCopy = new DefaultHostnameVerifier(publicSuffixMatcherCopy);
}
if (sslContext != null) {
sslSocketFactoryCopy = new SSLConnectionSocketFactory(
sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
} else {
if (systemProperties) {
sslSocketFactoryCopy = new SSLConnectionSocketFactory(
(SSLSocketFactory) SSLSocketFactory.getDefault(),
supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
} else {
sslSocketFactoryCopy = new SSLConnectionSocketFactory(
SSLContexts.createDefault(),
hostnameVerifierCopy);
}
}
}
@SuppressWarnings("resource")
final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslSocketFactoryCopy)
.build(),
null,
null,
null,
connTimeToLive,
connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS);
if (defaultSocketConfig != null) {
poolingmgr.setDefaultSocketConfig(defaultSocketConfig);
}
if (defaultConnectionConfig != null) {
poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig);
}
if (systemProperties) {
String s = System.getProperty("http.keepAlive", "true");
if ("true".equalsIgnoreCase(s)) {
s = System.getProperty("http.maxConnections", "5");
final int max = Integer.parseInt(s);
poolingmgr.setDefaultMaxPerRoute(max);
poolingmgr.setMaxTotal(2 * max);
}
}
if (maxConnTotal > 0) {
poolingmgr.setMaxTotal(maxConnTotal);
}
if (maxConnPerRoute > 0) {
poolingmgr.setDefaultMaxPerRoute(maxConnPerRoute);
}
connManagerCopy = poolingmgr;
}
ConnectionReuseStrategy reuseStrategyCopy = this.reuseStrategy;
if (reuseStrategyCopy == null) {
if (systemProperties) {
final String s = System.getProperty("http.keepAlive", "true");
if ("true".equalsIgnoreCase(s)) {
reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE;
} else {
reuseStrategyCopy = NoConnectionReuseStrategy.INSTANCE;
}
} else {
reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE;
}
}
ConnectionKeepAliveStrategy keepAliveStrategyCopy = this.keepAliveStrategy;
if (keepAliveStrategyCopy == null) {
keepAliveStrategyCopy = DefaultConnectionKeepAliveStrategy.INSTANCE;
}
AuthenticationStrategy targetAuthStrategyCopy = this.targetAuthStrategy;
if (targetAuthStrategyCopy == null) {
targetAuthStrategyCopy = TargetAuthenticationStrategy.INSTANCE;
}
AuthenticationStrategy proxyAuthStrategyCopy = this.proxyAuthStrategy;
if (proxyAuthStrategyCopy == null) {
proxyAuthStrategyCopy = ProxyAuthenticationStrategy.INSTANCE;
}
UserTokenHandler userTokenHandlerCopy = this.userTokenHandler;
if (userTokenHandlerCopy == null) {
if (!connectionStateDisabled) {
userTokenHandlerCopy = DefaultUserTokenHandler.INSTANCE;
} else {
userTokenHandlerCopy = NoopUserTokenHandler.INSTANCE;
}
}
String userAgentCopy = this.userAgent;
if (userAgentCopy == null) {
if (systemProperties) {
userAgentCopy = System.getProperty("http.agent");
}
if (userAgentCopy == null) {
userAgentCopy = VersionInfo.getUserAgent("Apache-HttpClient",
"org.apache.http.client", getClass());
}
}
ClientExecChain execChain = createMainExec(
requestExecCopy,
connManagerCopy,
reuseStrategyCopy,
keepAliveStrategyCopy,
new ImmutableHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
targetAuthStrategyCopy,
proxyAuthStrategyCopy,
userTokenHandlerCopy);
execChain = decorateMainExec(execChain);
HttpProcessor httpprocessorCopy = this.httpprocessor;
if (httpprocessorCopy == null) {
final HttpProcessorBuilder b = HttpProcessorBuilder.create();
if (requestFirst != null) {
for (final HttpRequestInterceptor i: requestFirst) {
b.addFirst(i);
}
}
if (responseFirst != null) {
for (final HttpResponseInterceptor i: responseFirst) {
b.addFirst(i);
}
}
b.addAll(
new RequestDefaultHeaders(defaultHeaders),
new RequestContent(),
new RequestTargetHost(),
new RequestClientConnControl(),
new RequestUserAgent(userAgentCopy),
new RequestExpectContinue());
if (!cookieManagementDisabled) {
b.add(new RequestAddCookies());
}
if (!contentCompressionDisabled) {
if (contentDecoderMap != null) {
final List<String> encodings = new ArrayList<String>(contentDecoderMap.keySet());
Collections.sort(encodings);
b.add(new RequestAcceptEncoding(encodings));
} else {
b.add(new RequestAcceptEncoding());
}
}
if (!authCachingDisabled) {
b.add(new RequestAuthCache());
}
if (!cookieManagementDisabled) {
b.add(new ResponseProcessCookies());
}
if (!contentCompressionDisabled) {
if (contentDecoderMap != null) {
final RegistryBuilder<InputStreamFactory> b2 = RegistryBuilder.create();
for (Map.Entry<String, InputStreamFactory> entry: contentDecoderMap.entrySet()) {
b2.register(entry.getKey(), entry.getValue());
}
b.add(new ResponseContentEncoding(b2.build()));
} else {
b.add(new ResponseContentEncoding());
}
}
if (requestLast != null) {
for (final HttpRequestInterceptor i: requestLast) {
b.addLast(i);
}
}
if (responseLast != null) {
for (final HttpResponseInterceptor i: responseLast) {
b.addLast(i);
}
}
httpprocessorCopy = b.build();
}
execChain = new ProtocolExec(execChain, httpprocessorCopy);
execChain = decorateProtocolExec(execChain);
// Add request retry executor, if not disabled
if (!automaticRetriesDisabled) {
HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;
if (retryHandlerCopy == null) {
retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE;
}
execChain = new RetryExec(execChain, retryHandlerCopy);
}
HttpRoutePlanner routePlannerCopy = this.routePlanner;
if (routePlannerCopy == null) {
SchemePortResolver schemePortResolverCopy = this.schemePortResolver;
if (schemePortResolverCopy == null) {
schemePortResolverCopy = DefaultSchemePortResolver.INSTANCE;
}
if (proxy != null) {
routePlannerCopy = new DefaultProxyRoutePlanner(proxy, schemePortResolverCopy);
} else if (systemProperties) {
routePlannerCopy = new SystemDefaultRoutePlanner(
schemePortResolverCopy, ProxySelector.getDefault());
} else {
routePlannerCopy = new DefaultRoutePlanner(schemePortResolverCopy);
}
}
// Add redirect executor, if not disabled
if (!redirectHandlingDisabled) {
RedirectStrategy redirectStrategyCopy = this.redirectStrategy;
if (redirectStrategyCopy == null) {
redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE;
}
execChain = new RedirectExec(execChain, routePlannerCopy, redirectStrategyCopy);
}
// Optionally, add service unavailable retry executor
final ServiceUnavailableRetryStrategy serviceUnavailStrategyCopy = this.serviceUnavailStrategy;
if (serviceUnavailStrategyCopy != null) {
execChain = new ServiceUnavailableRetryExec(execChain, serviceUnavailStrategyCopy);
}
// Optionally, add connection back-off executor
if (this.backoffManager != null && this.connectionBackoffStrategy != null) {
execChain = new BackoffStrategyExec(execChain, this.connectionBackoffStrategy, this.backoffManager);
}
Lookup<AuthSchemeProvider> authSchemeRegistryCopy = this.authSchemeRegistry;
if (authSchemeRegistryCopy == null) {
authSchemeRegistryCopy = RegistryBuilder.<AuthSchemeProvider>create()
.register(AuthSchemes.BASIC, new BasicSchemeFactory())
.register(AuthSchemes.DIGEST, new DigestSchemeFactory())
.register(AuthSchemes.NTLM, new NTLMSchemeFactory())
.register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory())
.register(AuthSchemes.KERBEROS, new KerberosSchemeFactory())
.build();
}
Lookup<CookieSpecProvider> cookieSpecRegistryCopy = this.cookieSpecRegistry;
if (cookieSpecRegistryCopy == null) {
cookieSpecRegistryCopy = CookieSpecRegistries.createDefault(publicSuffixMatcherCopy);
}
CookieStore defaultCookieStore = this.cookieStore;
if (defaultCookieStore == null) {
defaultCookieStore = new BasicCookieStore();
}
CredentialsProvider defaultCredentialsProvider = this.credentialsProvider;
if (defaultCredentialsProvider == null) {
if (systemProperties) {
defaultCredentialsProvider = new SystemDefaultCredentialsProvider();
} else {
defaultCredentialsProvider = new BasicCredentialsProvider();
}
}
List<Closeable> closeablesCopy = closeables != null ? new ArrayList<Closeable>(closeables) : null;
if (!this.connManagerShared) {
if (closeablesCopy == null) {
closeablesCopy = new ArrayList<Closeable>(1);
}
final HttpClientConnectionManager cm = connManagerCopy;
if (evictExpiredConnections || evictIdleConnections) {
final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
maxIdleTime > 0 ? maxIdleTime : 10, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS);
closeablesCopy.add(new Closeable() {
@Override
public void close() throws IOException {
connectionEvictor.shutdown();
}
});
connectionEvictor.start();
}
closeablesCopy.add(new Closeable() {
@Override
public void close() throws IOException {
cm.shutdown();
}
});
}
return new InternalHttpClient(
execChain,
connManagerCopy,
routePlannerCopy,
cookieSpecRegistryCopy,
authSchemeRegistryCopy,
defaultCookieStore,
defaultCredentialsProvider,
defaultRequestConfig != null ? defaultRequestConfig : RequestConfig.DEFAULT,
closeablesCopy);
}
可以看到,這個方法,真的很長很長,特別多,最後返回的是一個InternalHttpClient對象,這個應該就是實現了HttpClient接口的實例了。
@ThreadSafe
@SuppressWarnings("deprecation")
class InternalHttpClient extends CloseableHttpClient implements Configurable {
private final Log log = LogFactory.getLog(getClass());
private final ClientExecChain execChain;
private final HttpClientConnectionManager connManager;
private final HttpRoutePlanner routePlanner;
private final Lookup<CookieSpecProvider> cookieSpecRegistry;
private final Lookup<AuthSchemeProvider> authSchemeRegistry;
private final CookieStore cookieStore;
private final CredentialsProvider credentialsProvider;
private final RequestConfig defaultConfig;
private final List<Closeable> closeables;
public InternalHttpClient(
final ClientExecChain execChain,
final HttpClientConnectionManager connManager,
final HttpRoutePlanner routePlanner,
final Lookup<CookieSpecProvider> cookieSpecRegistry,
final Lookup<AuthSchemeProvider> authSchemeRegistry,
final CookieStore cookieStore,
final CredentialsProvider credentialsProvider,
final RequestConfig defaultConfig,
final List<Closeable> closeables) {
super();
Args.notNull(execChain, "HTTP client exec chain");
Args.notNull(connManager, "HTTP connection manager");
Args.notNull(routePlanner, "HTTP route planner");
this.execChain = execChain;
this.connManager = connManager;
this.routePlanner = routePlanner;
this.cookieSpecRegistry = cookieSpecRegistry;
this.authSchemeRegistry = authSchemeRegistry;
this.cookieStore = cookieStore;
this.credentialsProvider = credentialsProvider;
this.defaultConfig = defaultConfig;
this.closeables = closeables;
}
private HttpRoute determineRoute(
final HttpHost target,
final HttpRequest request,
final HttpContext context) throws HttpException {
HttpHost host = target;
if (host == null) {
host = (HttpHost) request.getParams().getParameter(ClientPNames.DEFAULT_HOST);
}
return this.routePlanner.determineRoute(host, request, context);
}
private void setupContext(final HttpClientContext context) {
if (context.getAttribute(HttpClientContext.TARGET_AUTH_STATE) == null) {
context.setAttribute(HttpClientContext.TARGET_AUTH_STATE, new AuthState());
}
if (context.getAttribute(HttpClientContext.PROXY_AUTH_STATE) == null) {
context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, new AuthState());
}
if (context.getAttribute(HttpClientContext.AUTHSCHEME_REGISTRY) == null) {
context.setAttribute(HttpClientContext.AUTHSCHEME_REGISTRY, this.authSchemeRegistry);
}
if (context.getAttribute(HttpClientContext.COOKIESPEC_REGISTRY) == null) {
context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
}
if (context.getAttribute(HttpClientContext.COOKIE_STORE) == null) {
context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
}
if (context.getAttribute(HttpClientContext.CREDS_PROVIDER) == null) {
context.setAttribute(HttpClientContext.CREDS_PROVIDER, this.credentialsProvider);
}
if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
context.setAttribute(HttpClientContext.REQUEST_CONFIG, this.defaultConfig);
}
}
@Override
protected CloseableHttpResponse doExecute(
final HttpHost target,
final HttpRequest request,
final HttpContext context) throws IOException, ClientProtocolException {
Args.notNull(request, "HTTP request");
HttpExecutionAware execAware = null;
if (request instanceof HttpExecutionAware) {
execAware = (HttpExecutionAware) request;
}
try {
final HttpRequestWrapper wrapper = HttpRequestWrapper.wrap(request, target);
final HttpClientContext localcontext = HttpClientContext.adapt(
context != null ? context : new BasicHttpContext());
RequestConfig config = null;
if (request instanceof Configurable) {
config = ((Configurable) request).getConfig();
}
if (config == null) {
final HttpParams params = request.getParams();
if (params instanceof HttpParamsNames) {
if (!((HttpParamsNames) params).getNames().isEmpty()) {
config = HttpClientParamConfig.getRequestConfig(params);
}
} else {
config = HttpClientParamConfig.getRequestConfig(params);
}
}
if (config != null) {
localcontext.setRequestConfig(config);
}
setupContext(localcontext);
final HttpRoute route = determineRoute(target, wrapper, localcontext);
return this.execChain.execute(route, wrapper, localcontext, execAware);
} catch (final HttpException httpException) {
throw new ClientProtocolException(httpException);
}
}
@Override
public RequestConfig getConfig() {
return this.defaultConfig;
}
@Override
public void close() {
if (this.closeables != null) {
for (final Closeable closeable: this.closeables) {
try {
closeable.close();
} catch (final IOException ex) {
this.log.error(ex.getMessage(), ex);
}
}
}
}
@Override
public HttpParams getParams() {
throw new UnsupportedOperationException();
}
@Override
public ClientConnectionManager getConnectionManager() {
return new ClientConnectionManager() {
@Override
public void shutdown() {
connManager.shutdown();
}
@Override
public ClientConnectionRequest requestConnection(
final HttpRoute route, final Object state) {
throw new UnsupportedOperationException();
}
@Override
public void releaseConnection(
final ManagedClientConnection conn,
final long validDuration, final TimeUnit timeUnit) {
throw new UnsupportedOperationException();
}
@Override
public SchemeRegistry getSchemeRegistry() {
throw new UnsupportedOperationException();
}
@Override
public void closeIdleConnections(final long idletime, final TimeUnit tunit) {
connManager.closeIdleConnections(idletime, tunit);
}
@Override
public void closeExpiredConnections() {
connManager.closeExpiredConnections();
}
};
}
}
ps:看看,請求就是調用的這個實例裏面的doExecute方法,至於最後怎麼調用到這一步的,跟蹤源碼,找準實例,還是很容易找到的,這個我以後有空再寫一篇,分析一下Http請求的流程。總裏面還用了一個連接的管理類來管理連接,就不多說了。
傳入的參數,其實最終包含本地端口信息的是在構造函數的第一個參數
final ClientExecChain execChain
裏面。
我們還是回頭看看build()方法
final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslSocketFactoryCopy)
.build(),
null,
null,
null,
connTimeToLive,
connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS);
主要就是962行的這個,註冊了兩個工廠,一個是http請求的,一個是https請求的,https請求的工廠sslSocketFactoryCopy實例的創建,就和之前那個參數有關,我就不多說了,看源碼很快就能發現。
http的工廠 PlainConnectionSocketFactory,這個我們進去看一下
@Immutable
public class PlainConnectionSocketFactory implements ConnectionSocketFactory {
public static final PlainConnectionSocketFactory INSTANCE = new PlainConnectionSocketFactory();
public static PlainConnectionSocketFactory getSocketFactory() {
return INSTANCE;
}
public PlainConnectionSocketFactory() {
super();
}
@Override
public Socket createSocket(final HttpContext context) throws IOException {
return new Socket();
}
@Override
public Socket connectSocket(
final int connectTimeout,
final Socket socket,
final HttpHost host,
final InetSocketAddress remoteAddress,
final InetSocketAddress localAddress,
final HttpContext context) throws IOException {
final Socket sock = socket != null ? socket : createSocket(context);
if (localAddress != null) {
sock.bind(localAddress);
}
try {
sock.connect(remoteAddress, connectTimeout);
} catch (final IOException ex) {
try {
sock.close();
} catch (final IOException ignore) {
}
throw ex;
}
return sock;
}
}
可以看到,這個類很小,行數也不多,方法也不多
第一個:createSocket(final HttpContext context)
這裏可以看到直接new了一個socket返回去了
第二個:
public Socket connectSocket(
final int connectTimeout,
final Socket socket,
final HttpHost host,
final InetSocketAddress remoteAddress,
final InetSocketAddress localAddress,
final HttpContext context) throws IOException {
final Socket sock = socket != null ? socket : createSocket(context);
if (localAddress != null) {
sock.bind(localAddress);
}
try {
sock.connect(remoteAddress, connectTimeout);
} catch (final IOException ex) {
try {
sock.close();
} catch (final IOException ignore) {
}
throw ex;
}
return sock;
}
這個就是建立socket的連接具體實現方法,可以看到,這個方法調用的時候,還可以傳入本地ip端口信息,進行socket綁定,但是也就是從這個方法,可以追溯到之前HttpClient實例類InternalHttpClient構造函數的第一個參數final ClientExecChain execChain,具體可以看PoolingHttpClientConnectionManager類裏面的connect()方法。
走第二個方法,摻入參數,涉及到的類特別多,參數傳入很複雜,還有很多轉換的地方,有興趣看源碼的朋友可以瞭解一下
所以我選擇了走第一個方法,重寫這個方法就行啦,結果,這個坑啊
首先,HttpClientBuilder,PlainConnectionSocketFactory,這些需要修改的類,都是源碼沒辦法修改,只有自己寫了,InternalHttpClient不是public的,只能在源碼包下用,只能自己新建一個了。
這個就是代替InternalHttpClient類的
@ThreadSafe
@SuppressWarnings("deprecation")
public class BindPortCloseableHttpClient extends CloseableHttpClient implements Configurable {
private final Log log = LogFactory.getLog(getClass());
private final ClientExecChain execChain;
private final HttpClientConnectionManager connManager;
private final HttpRoutePlanner routePlanner;
private final Lookup<CookieSpecProvider> cookieSpecRegistry;
private final Lookup<AuthSchemeProvider> authSchemeRegistry;
private final CookieStore cookieStore;
private final CredentialsProvider credentialsProvider;
private final RequestConfig defaultConfig;
private final List<Closeable> closeables;
public BindPortCloseableHttpClient(
final ClientExecChain execChain,
final HttpClientConnectionManager connManager,
final HttpRoutePlanner routePlanner,
final Lookup<CookieSpecProvider> cookieSpecRegistry,
final Lookup<AuthSchemeProvider> authSchemeRegistry,
final CookieStore cookieStore,
final CredentialsProvider credentialsProvider,
final RequestConfig defaultConfig,
final List<Closeable> closeables) {
super();
Args.notNull(execChain, "HTTP client exec chain");
Args.notNull(connManager, "HTTP connection manager");
Args.notNull(routePlanner, "HTTP route planner");
this.execChain = execChain;
this.connManager = connManager;
this.routePlanner = routePlanner;
this.cookieSpecRegistry = cookieSpecRegistry;
this.authSchemeRegistry = authSchemeRegistry;
this.cookieStore = cookieStore;
this.credentialsProvider = credentialsProvider;
this.defaultConfig = defaultConfig;
this.closeables = closeables;
}
private HttpRoute determineRoute(
final HttpHost target,
final HttpRequest request,
final HttpContext context) throws HttpException {
HttpHost host = target;
if (host == null) {
host = (HttpHost) request.getParams().getParameter(ClientPNames.DEFAULT_HOST);
}
return this.routePlanner.determineRoute(host, request, context);
}
private void setupContext(final HttpClientContext context) {
if (context.getAttribute(HttpClientContext.TARGET_AUTH_STATE) == null) {
context.setAttribute(HttpClientContext.TARGET_AUTH_STATE, new AuthState());
}
if (context.getAttribute(HttpClientContext.PROXY_AUTH_STATE) == null) {
context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, new AuthState());
}
if (context.getAttribute(HttpClientContext.AUTHSCHEME_REGISTRY) == null) {
context.setAttribute(HttpClientContext.AUTHSCHEME_REGISTRY, this.authSchemeRegistry);
}
if (context.getAttribute(HttpClientContext.COOKIESPEC_REGISTRY) == null) {
context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
}
if (context.getAttribute(HttpClientContext.COOKIE_STORE) == null) {
context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
}
if (context.getAttribute(HttpClientContext.CREDS_PROVIDER) == null) {
context.setAttribute(HttpClientContext.CREDS_PROVIDER, this.credentialsProvider);
}
if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
context.setAttribute(HttpClientContext.REQUEST_CONFIG, this.defaultConfig);
}
}
@Override
protected CloseableHttpResponse doExecute(
final HttpHost target,
final HttpRequest request,
final HttpContext context) throws IOException, ClientProtocolException {
Args.notNull(request, "HTTP request");
HttpExecutionAware execAware = null;
if (request instanceof HttpExecutionAware) {
execAware = (HttpExecutionAware) request;
}
try {
final HttpRequestWrapper wrapper = HttpRequestWrapper.wrap(request, target);
final HttpClientContext localcontext = HttpClientContext.adapt(
context != null ? context : new BasicHttpContext());
RequestConfig config = null;
if (request instanceof Configurable) {
config = ((Configurable) request).getConfig();
}
if (config == null) {
final HttpParams params = request.getParams();
if (params instanceof HttpParamsNames) {
if (!((HttpParamsNames) params).getNames().isEmpty()) {
config = HttpClientParamConfig.getRequestConfig(params);
}
} else {
config = HttpClientParamConfig.getRequestConfig(params);
}
}
if (config != null) {
localcontext.setRequestConfig(config);
}
setupContext(localcontext);
final HttpRoute route = determineRoute(target, wrapper, localcontext);
return this.execChain.execute(route, wrapper, localcontext, execAware);
} catch (final HttpException httpException) {
throw new ClientProtocolException(httpException);
}
}
@Override
public RequestConfig getConfig() {
return this.defaultConfig;
}
@Override
public void close() {
if (this.closeables != null) {
for (final Closeable closeable: this.closeables) {
try {
closeable.close();
} catch (final IOException ex) {
this.log.error(ex.getMessage(), ex);
}
}
}
}
@Override
public HttpParams getParams() {
throw new UnsupportedOperationException();
}
@Override
public ClientConnectionManager getConnectionManager() {
return new ClientConnectionManager() {
@Override
public void shutdown() {
connManager.shutdown();
}
@Override
public ClientConnectionRequest requestConnection(
final HttpRoute route, final Object state) {
throw new UnsupportedOperationException();
}
@Override
public void releaseConnection(
final ManagedClientConnection conn,
final long validDuration, final TimeUnit timeUnit) {
throw new UnsupportedOperationException();
}
@Override
public SchemeRegistry getSchemeRegistry() {
throw new UnsupportedOperationException();
}
@Override
public void closeIdleConnections(final long idletime, final TimeUnit tunit) {
connManager.closeIdleConnections(idletime, tunit);
}
@Override
public void closeExpiredConnections() {
connManager.closeExpiredConnections();
}
};
}
}
這是代替PlainConnectionSocketFactory的
public class BindPortConnectSocketFactory implements ConnectionSocketFactory {
public static final BindPortConnectSocketFactory INSTANCE = new BindPortConnectSocketFactory();
public static BindPortConnectSocketFactory getSocketFactory() {
return INSTANCE;
}
public BindPortConnectSocketFactory() {
super();
}
@Override
public Socket createSocket(HttpContext context) throws IOException {
Socket socket = new Socket();
socket.bind(new InetSocketAddress(10011));
System.out.println("port = [" + socket.getPort() + "]");
System.out.println("socket.getLocalPort() = [" + socket.getLocalPort() + "]");
return socket;
}
@Override
public Socket connectSocket(
int connectTimeout,
Socket socket,
HttpHost host,
InetSocketAddress remoteAddress,
InetSocketAddress localAddress,
HttpContext context) throws IOException {
System.out.println("port22 = [" + socket.getPort() + "]");
System.out.println("localAddress = [" + localAddress + "]");
System.out.println("socket = [" + socket.hashCode() + "]");
final Socket sock = socket != null ? socket : createSocket(context);
if (localAddress != null) {
sock.bind(localAddress);
}
try {
sock.connect(remoteAddress, connectTimeout);
} catch (final IOException ex) {
try {
sock.close();
} catch (final IOException ignore) {
}
throw ex;
}
return sock;
}
}
這裏修改了第一個方法的內容,綁定了端口,以後可以把端口放到配置文件裏面配置
這個是代替HttpClientBuilder的
public class BindPortHttpClientBuilder {
private HttpRequestExecutor requestExec;
private HostnameVerifier hostnameVerifier;
private LayeredConnectionSocketFactory sslSocketFactory;
private SSLContext sslContext;
private HttpClientConnectionManager connManager;
private boolean connManagerShared;
private SchemePortResolver schemePortResolver;
private ConnectionReuseStrategy reuseStrategy;
private ConnectionKeepAliveStrategy keepAliveStrategy;
private AuthenticationStrategy targetAuthStrategy;
private AuthenticationStrategy proxyAuthStrategy;
private UserTokenHandler userTokenHandler;
private HttpProcessor httpprocessor;
private LinkedList<HttpRequestInterceptor> requestFirst;
private LinkedList<HttpRequestInterceptor> requestLast;
private LinkedList<HttpResponseInterceptor> responseFirst;
private LinkedList<HttpResponseInterceptor> responseLast;
private HttpRequestRetryHandler retryHandler;
private HttpRoutePlanner routePlanner;
private RedirectStrategy redirectStrategy;
private ConnectionBackoffStrategy connectionBackoffStrategy;
private BackoffManager backoffManager;
private ServiceUnavailableRetryStrategy serviceUnavailStrategy;
private Lookup<AuthSchemeProvider> authSchemeRegistry;
private Lookup<CookieSpecProvider> cookieSpecRegistry;
private Map<String, InputStreamFactory> contentDecoderMap;
private CookieStore cookieStore;
private CredentialsProvider credentialsProvider;
private String userAgent;
private HttpHost proxy;
private Collection<? extends Header> defaultHeaders;
private SocketConfig defaultSocketConfig;
private ConnectionConfig defaultConnectionConfig;
private RequestConfig defaultRequestConfig;
private boolean evictExpiredConnections;
private boolean evictIdleConnections;
private long maxIdleTime;
private TimeUnit maxIdleTimeUnit;
private boolean systemProperties;
private boolean redirectHandlingDisabled;
private boolean automaticRetriesDisabled;
private boolean contentCompressionDisabled;
private boolean cookieManagementDisabled;
private boolean authCachingDisabled;
private boolean connectionStateDisabled;
private int maxConnTotal = 0;
private int maxConnPerRoute = 0;
private long connTimeToLive = -1;
private TimeUnit connTimeToLiveTimeUnit = TimeUnit.MILLISECONDS;
private List<Closeable> closeables;
private PublicSuffixMatcher publicSuffixMatcher;
public static BindPortHttpClientBuilder create() {
return new BindPortHttpClientBuilder();
}
protected BindPortHttpClientBuilder() {
super();
}
/**
* Assigns {@link HttpRequestExecutor} instance.
*/
public final BindPortHttpClientBuilder setRequestExecutor(final HttpRequestExecutor requestExec) {
this.requestExec = requestExec;
return this;
}
/**
* Assigns {@link X509HostnameVerifier} instance.
* <p>
* Please note this value can be overridden by the {@link #setConnectionManager(
* org.apache.http.conn.HttpClientConnectionManager)} and the {@link #setSSLSocketFactory(
* org.apache.http.conn.socket.LayeredConnectionSocketFactory)} methods.
* </p>
*
* @deprecated (4.4)
*/
@Deprecated
public final BindPortHttpClientBuilder setHostnameVerifier(final X509HostnameVerifier hostnameVerifier) {
this.hostnameVerifier = hostnameVerifier;
return this;
}
/**
* Assigns {@link javax.net.ssl.HostnameVerifier} instance.
* <p>
* Please note this value can be overridden by the {@link #setConnectionManager(
* org.apache.http.conn.HttpClientConnectionManager)} and the {@link #setSSLSocketFactory(
* org.apache.http.conn.socket.LayeredConnectionSocketFactory)} methods.
* </p>
*
* @since 4.4
*/
public final BindPortHttpClientBuilder setSSLHostnameVerifier(final HostnameVerifier hostnameVerifier) {
this.hostnameVerifier = hostnameVerifier;
return this;
}
/**
* Assigns file containing public suffix matcher. Instances of this class can be created
* with {@link org.apache.http.conn.util.PublicSuffixMatcherLoader}.
*
* @see org.apache.http.conn.util.PublicSuffixMatcher
* @see org.apache.http.conn.util.PublicSuffixMatcherLoader
*
* @since 4.4
*/
public final BindPortHttpClientBuilder setPublicSuffixMatcher(final PublicSuffixMatcher publicSuffixMatcher) {
this.publicSuffixMatcher = publicSuffixMatcher;
return this;
}
/**
* Assigns {@link SSLContext} instance.
* <p>
* Please note this value can be overridden by the {@link #setConnectionManager(
* org.apache.http.conn.HttpClientConnectionManager)} and the {@link #setSSLSocketFactory(
* org.apache.http.conn.socket.LayeredConnectionSocketFactory)} methods.
* </p>
*
* @deprecated (4.5) use {@link #setSSLContext(SSLContext)}
*/
@Deprecated
public final BindPortHttpClientBuilder setSslcontext(final SSLContext sslcontext) {
return setSSLContext(sslcontext);
}
/**
* Assigns {@link SSLContext} instance.
* <p>
* Please note this value can be overridden by the {@link #setConnectionManager(
* org.apache.http.conn.HttpClientConnectionManager)} and the {@link #setSSLSocketFactory(
* org.apache.http.conn.socket.LayeredConnectionSocketFactory)} methods.
* </p>
*/
public final BindPortHttpClientBuilder setSSLContext(final SSLContext sslContext) {
this.sslContext = sslContext;
return this;
}
/**
* Assigns {@link LayeredConnectionSocketFactory} instance.
* <p>
* Please note this value can be overridden by the {@link #setConnectionManager(
* org.apache.http.conn.HttpClientConnectionManager)} method.
* </p>
*/
public final BindPortHttpClientBuilder setSSLSocketFactory(
final LayeredConnectionSocketFactory sslSocketFactory) {
this.sslSocketFactory = sslSocketFactory;
return this;
}
/**
* Assigns maximum total connection value.
* <p>
* Please note this value can be overridden by the {@link #setConnectionManager(
* org.apache.http.conn.HttpClientConnectionManager)} method.
* </p>
*/
public final BindPortHttpClientBuilder setMaxConnTotal(final int maxConnTotal) {
this.maxConnTotal = maxConnTotal;
return this;
}
/**
* Assigns maximum connection per route value.
* <p>
* Please note this value can be overridden by the {@link #setConnectionManager(
* org.apache.http.conn.HttpClientConnectionManager)} method.
* </p>
*/
public final BindPortHttpClientBuilder setMaxConnPerRoute(final int maxConnPerRoute) {
this.maxConnPerRoute = maxConnPerRoute;
return this;
}
/**
* Assigns default {@link SocketConfig}.
* <p>
* Please note this value can be overridden by the {@link #setConnectionManager(
* org.apache.http.conn.HttpClientConnectionManager)} method.
* </p>
*/
public final BindPortHttpClientBuilder setDefaultSocketConfig(final SocketConfig config) {
this.defaultSocketConfig = config;
return this;
}
/**
* Assigns default {@link ConnectionConfig}.
* <p>
* Please note this value can be overridden by the {@link #setConnectionManager(
* org.apache.http.conn.HttpClientConnectionManager)} method.
* </p>
*/
public final BindPortHttpClientBuilder setDefaultConnectionConfig(final ConnectionConfig config) {
this.defaultConnectionConfig = config;
return this;
}
/**
* Sets maximum time to live for persistent connections
* <p>
* Please note this value can be overridden by the {@link #setConnectionManager(
* org.apache.http.conn.HttpClientConnectionManager)} method.
* </p>
*
* @since 4.4
*/
public final BindPortHttpClientBuilder setConnectionTimeToLive(final long connTimeToLive, final TimeUnit connTimeToLiveTimeUnit) {
this.connTimeToLive = connTimeToLive;
this.connTimeToLiveTimeUnit = connTimeToLiveTimeUnit;
return this;
}
/**
* Assigns {@link HttpClientConnectionManager} instance.
*/
public final BindPortHttpClientBuilder setConnectionManager(
final HttpClientConnectionManager connManager) {
this.connManager = connManager;
return this;
}
/**
* Defines the connection manager is to be shared by multiple
* client instances.
* <p>
* If the connection manager is shared its life-cycle is expected
* to be managed by the caller and it will not be shut down
* if the client is closed.
* </p>
*
* @param shared defines whether or not the connection manager can be shared
* by multiple clients.
*
* @since 4.4
*/
public final BindPortHttpClientBuilder setConnectionManagerShared(
final boolean shared) {
this.connManagerShared = shared;
return this;
}
/**
* Assigns {@link ConnectionReuseStrategy} instance.
*/
public final BindPortHttpClientBuilder setConnectionReuseStrategy(
final ConnectionReuseStrategy reuseStrategy) {
this.reuseStrategy = reuseStrategy;
return this;
}
/**
* Assigns {@link ConnectionKeepAliveStrategy} instance.
*/
public final BindPortHttpClientBuilder setKeepAliveStrategy(
final ConnectionKeepAliveStrategy keepAliveStrategy) {
this.keepAliveStrategy = keepAliveStrategy;
return this;
}
/**
* Assigns {@link AuthenticationStrategy} instance for target
* host authentication.
*/
public final BindPortHttpClientBuilder setTargetAuthenticationStrategy(
final AuthenticationStrategy targetAuthStrategy) {
this.targetAuthStrategy = targetAuthStrategy;
return this;
}
/**
* Assigns {@link AuthenticationStrategy} instance for proxy
* authentication.
*/
public final BindPortHttpClientBuilder setProxyAuthenticationStrategy(
final AuthenticationStrategy proxyAuthStrategy) {
this.proxyAuthStrategy = proxyAuthStrategy;
return this;
}
/**
* Assigns {@link UserTokenHandler} instance.
* <p>
* Please note this value can be overridden by the {@link #disableConnectionState()}
* method.
* </p>
*/
public final BindPortHttpClientBuilder setUserTokenHandler(final UserTokenHandler userTokenHandler) {
this.userTokenHandler = userTokenHandler;
return this;
}
/**
* Disables connection state tracking.
*/
public final BindPortHttpClientBuilder disableConnectionState() {
connectionStateDisabled = true;
return this;
}
/**
* Assigns {@link SchemePortResolver} instance.
*/
public final BindPortHttpClientBuilder setSchemePortResolver(
final SchemePortResolver schemePortResolver) {
this.schemePortResolver = schemePortResolver;
return this;
}
/**
* Assigns {@code User-Agent} value.
* <p>
* Please note this value can be overridden by the {@link #setHttpProcessor(
* org.apache.http.protocol.HttpProcessor)} method.
* </p>
*/
public final BindPortHttpClientBuilder setUserAgent(final String userAgent) {
this.userAgent = userAgent;
return this;
}
/**
* Assigns default request header values.
* <p>
* Please note this value can be overridden by the {@link #setHttpProcessor(
* org.apache.http.protocol.HttpProcessor)} method.
* </p>
*/
public final BindPortHttpClientBuilder setDefaultHeaders(final Collection<? extends Header> defaultHeaders) {
this.defaultHeaders = defaultHeaders;
return this;
}
/**
* Adds this protocol interceptor to the head of the protocol processing list.
* <p>
* Please note this value can be overridden by the {@link #setHttpProcessor(
* org.apache.http.protocol.HttpProcessor)} method.
* </p>
*/
public final BindPortHttpClientBuilder addInterceptorFirst(final HttpResponseInterceptor itcp) {
if (itcp == null) {
return this;
}
if (responseFirst == null) {
responseFirst = new LinkedList<HttpResponseInterceptor>();
}
responseFirst.addFirst(itcp);
return this;
}
/**
* Adds this protocol interceptor to the tail of the protocol processing list.
* <p>
* Please note this value can be overridden by the {@link #setHttpProcessor(
* org.apache.http.protocol.HttpProcessor)} method.
* </p>
*/
public final BindPortHttpClientBuilder addInterceptorLast(final HttpResponseInterceptor itcp) {
if (itcp == null) {
return this;
}
if (responseLast == null) {
responseLast = new LinkedList<HttpResponseInterceptor>();
}
responseLast.addLast(itcp);
return this;
}
/**
* Adds this protocol interceptor to the head of the protocol processing list.
* <p>
* Please note this value can be overridden by the {@link #setHttpProcessor(
* org.apache.http.protocol.HttpProcessor)} method.
*/
public final BindPortHttpClientBuilder addInterceptorFirst(final HttpRequestInterceptor itcp) {
if (itcp == null) {
return this;
}
if (requestFirst == null) {
requestFirst = new LinkedList<HttpRequestInterceptor>();
}
requestFirst.addFirst(itcp);
return this;
}
/**
* Adds this protocol interceptor to the tail of the protocol processing list.
* <p>
* Please note this value can be overridden by the {@link #setHttpProcessor(
* org.apache.http.protocol.HttpProcessor)} method.
*/
public final BindPortHttpClientBuilder addInterceptorLast(final HttpRequestInterceptor itcp) {
if (itcp == null) {
return this;
}
if (requestLast == null) {
requestLast = new LinkedList<HttpRequestInterceptor>();
}
requestLast.addLast(itcp);
return this;
}
/**
* Disables state (cookie) management.
* <p>
* Please note this value can be overridden by the {@link #setHttpProcessor(
* org.apache.http.protocol.HttpProcessor)} method.
*/
public final BindPortHttpClientBuilder disableCookieManagement() {
this.cookieManagementDisabled = true;
return this;
}
/**
* Disables automatic content decompression.
* <p>
* Please note this value can be overridden by the {@link #setHttpProcessor(
* org.apache.http.protocol.HttpProcessor)} method.
*/
public final BindPortHttpClientBuilder disableContentCompression() {
contentCompressionDisabled = true;
return this;
}
/**
* Disables authentication scheme caching.
* <p>
* Please note this value can be overridden by the {@link #setHttpProcessor(
* org.apache.http.protocol.HttpProcessor)} method.
*/
public final BindPortHttpClientBuilder disableAuthCaching() {
this.authCachingDisabled = true;
return this;
}
/**
* Assigns {@link HttpProcessor} instance.
*/
public final BindPortHttpClientBuilder setHttpProcessor(final HttpProcessor httpprocessor) {
this.httpprocessor = httpprocessor;
return this;
}
/**
* Assigns {@link HttpRequestRetryHandler} instance.
* <p>
* Please note this value can be overridden by the {@link #disableAutomaticRetries()}
* method.
*/
public final BindPortHttpClientBuilder setRetryHandler(final HttpRequestRetryHandler retryHandler) {
this.retryHandler = retryHandler;
return this;
}
/**
* Disables automatic request recovery and re-execution.
*/
public final BindPortHttpClientBuilder disableAutomaticRetries() {
automaticRetriesDisabled = true;
return this;
}
/**
* Assigns default proxy value.
* <p>
* Please note this value can be overridden by the {@link #setRoutePlanner(
* org.apache.http.conn.routing.HttpRoutePlanner)} method.
*/
public final BindPortHttpClientBuilder setProxy(final HttpHost proxy) {
this.proxy = proxy;
return this;
}
/**
* Assigns {@link HttpRoutePlanner} instance.
*/
public final BindPortHttpClientBuilder setRoutePlanner(final HttpRoutePlanner routePlanner) {
this.routePlanner = routePlanner;
return this;
}
/**
* Assigns {@link RedirectStrategy} instance.
* <p>
* Please note this value can be overridden by the {@link #disableRedirectHandling()}
* method.
* </p>
` */
public final BindPortHttpClientBuilder setRedirectStrategy(final RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
return this;
}
/**
* Disables automatic redirect handling.
*/
public final BindPortHttpClientBuilder disableRedirectHandling() {
redirectHandlingDisabled = true;
return this;
}
/**
* Assigns {@link ConnectionBackoffStrategy} instance.
*/
public final BindPortHttpClientBuilder setConnectionBackoffStrategy(
final ConnectionBackoffStrategy connectionBackoffStrategy) {
this.connectionBackoffStrategy = connectionBackoffStrategy;
return this;
}
/**
* Assigns {@link BackoffManager} instance.
*/
public final BindPortHttpClientBuilder setBackoffManager(final BackoffManager backoffManager) {
this.backoffManager = backoffManager;
return this;
}
/**
* Assigns {@link ServiceUnavailableRetryStrategy} instance.
*/
public final BindPortHttpClientBuilder setServiceUnavailableRetryStrategy(
final ServiceUnavailableRetryStrategy serviceUnavailStrategy) {
this.serviceUnavailStrategy = serviceUnavailStrategy;
return this;
}
/**
* Assigns default {@link CookieStore} instance which will be used for
* request execution if not explicitly set in the client execution context.
*/
public final BindPortHttpClientBuilder setDefaultCookieStore(final CookieStore cookieStore) {
this.cookieStore = cookieStore;
return this;
}
/**
* Assigns default {@link CredentialsProvider} instance which will be used
* for request execution if not explicitly set in the client execution
* context.
*/
public final BindPortHttpClientBuilder setDefaultCredentialsProvider(
final CredentialsProvider credentialsProvider) {
this.credentialsProvider = credentialsProvider;
return this;
}
/**
* Assigns default {@link org.apache.http.auth.AuthScheme} registry which will
* be used for request execution if not explicitly set in the client execution
* context.
*/
public final BindPortHttpClientBuilder setDefaultAuthSchemeRegistry(
final Lookup<AuthSchemeProvider> authSchemeRegistry) {
this.authSchemeRegistry = authSchemeRegistry;
return this;
}
/**
* Assigns default {@link org.apache.http.cookie.CookieSpec} registry which will
* be used for request execution if not explicitly set in the client execution
* context.
*
* @see org.apache.http.impl.client.CookieSpecRegistries
*
*/
public final BindPortHttpClientBuilder setDefaultCookieSpecRegistry(
final Lookup<CookieSpecProvider> cookieSpecRegistry) {
this.cookieSpecRegistry = cookieSpecRegistry;
return this;
}
/**
* Assigns a map of {@link org.apache.http.client.entity.InputStreamFactory}s
* to be used for automatic content decompression.
*/
public final BindPortHttpClientBuilder setContentDecoderRegistry(
final Map<String, InputStreamFactory> contentDecoderMap) {
this.contentDecoderMap = contentDecoderMap;
return this;
}
/**
* Assigns default {@link RequestConfig} instance which will be used
* for request execution if not explicitly set in the client execution
* context.
*/
public final BindPortHttpClientBuilder setDefaultRequestConfig(final RequestConfig config) {
this.defaultRequestConfig = config;
return this;
}
/**
* Use system properties when creating and configuring default
* implementations.
*/
public final BindPortHttpClientBuilder useSystemProperties() {
this.systemProperties = true;
return this;
}
/**
* Makes this instance of HttpClient proactively evict expired connections from the
* connection pool using a background thread.
* <p>
* One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
* to stop and release the background thread.
* <p>
* Please note this method has no effect if the instance of HttpClient is configuted to
* use a shared connection manager.
* <p>
* Please note this method may not be used when the instance of HttpClient is created
* inside an EJB container.
*
* @see #setConnectionManagerShared(boolean)
* @see org.apache.http.conn.HttpClientConnectionManager#closeExpiredConnections()
*
* @since 4.4
*/
public final BindPortHttpClientBuilder evictExpiredConnections() {
evictExpiredConnections = true;
return this;
}
/**
* Makes this instance of HttpClient proactively evict idle connections from the
* connection pool using a background thread.
* <p>
* One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
* to stop and release the background thread.
* <p>
* Please note this method has no effect if the instance of HttpClient is configuted to
* use a shared connection manager.
* <p>
* Please note this method may not be used when the instance of HttpClient is created
* inside an EJB container.
*
* @see #setConnectionManagerShared(boolean)
* @see org.apache.http.conn.HttpClientConnectionManager#closeExpiredConnections()
*
* @param maxIdleTime maximum time persistent connections can stay idle while kept alive
* in the connection pool. Connections whose inactivity period exceeds this value will
* get closed and evicted from the pool.
* @param maxIdleTimeUnit time unit for the above parameter.
*
* @deprecated (4.5) use {@link #evictIdleConnections(long, TimeUnit)}
*
* @since 4.4
*/
@Deprecated
public final BindPortHttpClientBuilder evictIdleConnections(final Long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
return evictIdleConnections(maxIdleTime.longValue(), maxIdleTimeUnit);
}
/**
* Makes this instance of HttpClient proactively evict idle connections from the
* connection pool using a background thread.
* <p>
* One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
* to stop and release the background thread.
* <p>
* Please note this method has no effect if the instance of HttpClient is configuted to
* use a shared connection manager.
* <p>
* Please note this method may not be used when the instance of HttpClient is created
* inside an EJB container.
*
* @see #setConnectionManagerShared(boolean)
* @see org.apache.http.conn.HttpClientConnectionManager#closeExpiredConnections()
*
* @param maxIdleTime maximum time persistent connections can stay idle while kept alive
* in the connection pool. Connections whose inactivity period exceeds this value will
* get closed and evicted from the pool.
* @param maxIdleTimeUnit time unit for the above parameter.
*
* @since 4.4
*/
public final BindPortHttpClientBuilder evictIdleConnections(final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
this.evictIdleConnections = true;
this.maxIdleTime = maxIdleTime;
this.maxIdleTimeUnit = maxIdleTimeUnit;
return this;
}
/**
* Produces an instance of {@link ClientExecChain} to be used as a main exec.
* <p>
* Default implementation produces an instance of {@link MainClientExec}
* </p>
* <p>
* For internal use.
* </p>
*
* @since 4.4
*/
protected ClientExecChain createMainExec(
final HttpRequestExecutor requestExec,
final HttpClientConnectionManager connManager,
final ConnectionReuseStrategy reuseStrategy,
final ConnectionKeepAliveStrategy keepAliveStrategy,
final HttpProcessor proxyHttpProcessor,
final AuthenticationStrategy targetAuthStrategy,
final AuthenticationStrategy proxyAuthStrategy,
final UserTokenHandler userTokenHandler)
{
return new MainClientExec(
requestExec,
connManager,
reuseStrategy,
keepAliveStrategy,
proxyHttpProcessor,
targetAuthStrategy,
proxyAuthStrategy,
userTokenHandler);
}
/**
* For internal use.
*/
protected ClientExecChain decorateMainExec(final ClientExecChain mainExec) {
return mainExec;
}
/**
* For internal use.
*/
protected ClientExecChain decorateProtocolExec(final ClientExecChain protocolExec) {
return protocolExec;
}
/**
* For internal use.
*/
protected void addCloseable(final Closeable closeable) {
if (closeable == null) {
return;
}
if (closeables == null) {
closeables = new ArrayList<Closeable>();
}
closeables.add(closeable);
}
private static String[] split(final String s) {
if (TextUtils.isBlank(s)) {
return null;
}
return s.split(" *, *");
}
public CloseableHttpClient build() {
// Create main request executor
// We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version
PublicSuffixMatcher publicSuffixMatcherCopy = this.publicSuffixMatcher;
if (publicSuffixMatcherCopy == null) {
publicSuffixMatcherCopy = PublicSuffixMatcherLoader.getDefault();
}
HttpRequestExecutor requestExecCopy = this.requestExec;
if (requestExecCopy == null) {
requestExecCopy = new HttpRequestExecutor();
}
HttpClientConnectionManager connManagerCopy = this.connManager;
if (connManagerCopy == null) {
LayeredConnectionSocketFactory sslSocketFactoryCopy = this.sslSocketFactory;
if (sslSocketFactoryCopy == null) {
final String[] supportedProtocols = systemProperties ? split(
System.getProperty("https.protocols")) : null;
final String[] supportedCipherSuites = systemProperties ? split(
System.getProperty("https.cipherSuites")) : null;
HostnameVerifier hostnameVerifierCopy = this.hostnameVerifier;
if (hostnameVerifierCopy == null) {
hostnameVerifierCopy = new DefaultHostnameVerifier(publicSuffixMatcherCopy);
}
if (sslContext != null) {
System.out.println("sslContext != null");
sslSocketFactoryCopy = new BindPortSSLConnrctSocketFactory(
sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
} else {
if (systemProperties) {
System.out.println("systemProperties = true");
sslSocketFactoryCopy = new BindPortSSLConnrctSocketFactory(
(SSLSocketFactory) SSLSocketFactory.getDefault(),
supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
} else {
System.out.println("systemProperties = false");
sslSocketFactoryCopy = new BindPortSSLConnrctSocketFactory(
SSLContexts.createDefault(),
hostnameVerifierCopy);
}
}
}
@SuppressWarnings("resource")
final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", BindPortConnectSocketFactory.getSocketFactory())
.register("https", sslSocketFactoryCopy)
.build(),
null,
null,
null,
connTimeToLive,
connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS);
if (defaultSocketConfig != null) {
poolingmgr.setDefaultSocketConfig(defaultSocketConfig);
}
if (defaultConnectionConfig != null) {
poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig);
}
if (systemProperties) {
String s = System.getProperty("http.keepAlive", "true");
if ("true".equalsIgnoreCase(s)) {
s = System.getProperty("http.maxConnections", "5");
final int max = Integer.parseInt(s);
poolingmgr.setDefaultMaxPerRoute(max);
poolingmgr.setMaxTotal(2 * max);
}
}
if (maxConnTotal > 0) {
poolingmgr.setMaxTotal(maxConnTotal);
}
if (maxConnPerRoute > 0) {
poolingmgr.setDefaultMaxPerRoute(maxConnPerRoute);
}
connManagerCopy = poolingmgr;
}
ConnectionReuseStrategy reuseStrategyCopy = this.reuseStrategy;
if (reuseStrategyCopy == null) {
if (systemProperties) {
final String s = System.getProperty("http.keepAlive", "true");
if ("true".equalsIgnoreCase(s)) {
reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE;
} else {
reuseStrategyCopy = NoConnectionReuseStrategy.INSTANCE;
}
} else {
reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE;
}
}
ConnectionKeepAliveStrategy keepAliveStrategyCopy = this.keepAliveStrategy;
if (keepAliveStrategyCopy == null) {
keepAliveStrategyCopy = DefaultConnectionKeepAliveStrategy.INSTANCE;
}
AuthenticationStrategy targetAuthStrategyCopy = this.targetAuthStrategy;
if (targetAuthStrategyCopy == null) {
targetAuthStrategyCopy = TargetAuthenticationStrategy.INSTANCE;
}
AuthenticationStrategy proxyAuthStrategyCopy = this.proxyAuthStrategy;
if (proxyAuthStrategyCopy == null) {
proxyAuthStrategyCopy = ProxyAuthenticationStrategy.INSTANCE;
}
UserTokenHandler userTokenHandlerCopy = this.userTokenHandler;
if (userTokenHandlerCopy == null) {
if (!connectionStateDisabled) {
userTokenHandlerCopy = DefaultUserTokenHandler.INSTANCE;
} else {
userTokenHandlerCopy = NoopUserTokenHandler.INSTANCE;
}
}
String userAgentCopy = this.userAgent;
if (userAgentCopy == null) {
if (systemProperties) {
userAgentCopy = System.getProperty("http.agent");
}
if (userAgentCopy == null) {
userAgentCopy = VersionInfo.getUserAgent("Apache-HttpClient",
"org.apache.http.client", getClass());
}
}
ClientExecChain execChain = createMainExec(
requestExecCopy,
connManagerCopy,
reuseStrategyCopy,
keepAliveStrategyCopy,
new ImmutableHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
targetAuthStrategyCopy,
proxyAuthStrategyCopy,
userTokenHandlerCopy);
execChain = decorateMainExec(execChain);
HttpProcessor httpprocessorCopy = this.httpprocessor;
if (httpprocessorCopy == null) {
final HttpProcessorBuilder b = HttpProcessorBuilder.create();
if (requestFirst != null) {
for (final HttpRequestInterceptor i: requestFirst) {
b.addFirst(i);
}
}
if (responseFirst != null) {
for (final HttpResponseInterceptor i: responseFirst) {
b.addFirst(i);
}
}
b.addAll(
new RequestDefaultHeaders(defaultHeaders),
new RequestContent(),
new RequestTargetHost(),
new RequestClientConnControl(),
new RequestUserAgent(userAgentCopy),
new RequestExpectContinue());
if (!cookieManagementDisabled) {
b.add(new RequestAddCookies());
}
if (!contentCompressionDisabled) {
if (contentDecoderMap != null) {
final List<String> encodings = new ArrayList<String>(contentDecoderMap.keySet());
Collections.sort(encodings);
b.add(new RequestAcceptEncoding(encodings));
} else {
b.add(new RequestAcceptEncoding());
}
}
if (!authCachingDisabled) {
b.add(new RequestAuthCache());
}
if (!cookieManagementDisabled) {
b.add(new ResponseProcessCookies());
}
if (!contentCompressionDisabled) {
if (contentDecoderMap != null) {
final RegistryBuilder<InputStreamFactory> b2 = RegistryBuilder.create();
for (Map.Entry<String, InputStreamFactory> entry: contentDecoderMap.entrySet()) {
b2.register(entry.getKey(), entry.getValue());
}
b.add(new ResponseContentEncoding(b2.build()));
} else {
b.add(new ResponseContentEncoding());
}
}
if (requestLast != null) {
for (final HttpRequestInterceptor i: requestLast) {
b.addLast(i);
}
}
if (responseLast != null) {
for (final HttpResponseInterceptor i: responseLast) {
b.addLast(i);
}
}
httpprocessorCopy = b.build();
}
execChain = new ProtocolExec(execChain, httpprocessorCopy);
execChain = decorateProtocolExec(execChain);
// Add request retry executor, if not disabled
if (!automaticRetriesDisabled) {
HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;
if (retryHandlerCopy == null) {
retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE;
}
execChain = new RetryExec(execChain, retryHandlerCopy);
}
HttpRoutePlanner routePlannerCopy = this.routePlanner;
if (routePlannerCopy == null) {
SchemePortResolver schemePortResolverCopy = this.schemePortResolver;
if (schemePortResolverCopy == null) {
schemePortResolverCopy = DefaultSchemePortResolver.INSTANCE;
}
if (proxy != null) {
routePlannerCopy = new DefaultProxyRoutePlanner(proxy, schemePortResolverCopy);
} else if (systemProperties) {
routePlannerCopy = new SystemDefaultRoutePlanner(
schemePortResolverCopy, ProxySelector.getDefault());
} else {
routePlannerCopy = new DefaultRoutePlanner(schemePortResolverCopy);
}
}
// Add redirect executor, if not disabled
if (!redirectHandlingDisabled) {
RedirectStrategy redirectStrategyCopy = this.redirectStrategy;
if (redirectStrategyCopy == null) {
redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE;
}
execChain = new RedirectExec(execChain, routePlannerCopy, redirectStrategyCopy);
}
// Optionally, add service unavailable retry executor
final ServiceUnavailableRetryStrategy serviceUnavailStrategyCopy = this.serviceUnavailStrategy;
if (serviceUnavailStrategyCopy != null) {
execChain = new ServiceUnavailableRetryExec(execChain, serviceUnavailStrategyCopy);
}
// Optionally, add connection back-off executor
if (this.backoffManager != null && this.connectionBackoffStrategy != null) {
execChain = new BackoffStrategyExec(execChain, this.connectionBackoffStrategy, this.backoffManager);
}
Lookup<AuthSchemeProvider> authSchemeRegistryCopy = this.authSchemeRegistry;
if (authSchemeRegistryCopy == null) {
authSchemeRegistryCopy = RegistryBuilder.<AuthSchemeProvider>create()
.register(AuthSchemes.BASIC, new BasicSchemeFactory())
.register(AuthSchemes.DIGEST, new DigestSchemeFactory())
.register(AuthSchemes.NTLM, new NTLMSchemeFactory())
.register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory())
.register(AuthSchemes.KERBEROS, new KerberosSchemeFactory())
.build();
}
Lookup<CookieSpecProvider> cookieSpecRegistryCopy = this.cookieSpecRegistry;
if (cookieSpecRegistryCopy == null) {
cookieSpecRegistryCopy = CookieSpecRegistries.createDefault(publicSuffixMatcherCopy);
}
CookieStore defaultCookieStore = this.cookieStore;
if (defaultCookieStore == null) {
defaultCookieStore = new BasicCookieStore();
}
CredentialsProvider defaultCredentialsProvider = this.credentialsProvider;
if (defaultCredentialsProvider == null) {
if (systemProperties) {
defaultCredentialsProvider = new SystemDefaultCredentialsProvider();
} else {
defaultCredentialsProvider = new BasicCredentialsProvider();
}
}
List<Closeable> closeablesCopy = closeables != null ? new ArrayList<Closeable>(closeables) : null;
if (!this.connManagerShared) {
if (closeablesCopy == null) {
closeablesCopy = new ArrayList<Closeable>(1);
}
final HttpClientConnectionManager cm = connManagerCopy;
if (evictExpiredConnections || evictIdleConnections) {
final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
maxIdleTime > 0 ? maxIdleTime : 10, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS);
closeablesCopy.add(new Closeable() {
@Override
public void close() throws IOException {
connectionEvictor.shutdown();
}
});
connectionEvictor.start();
}
closeablesCopy.add(new Closeable() {
@Override
public void close() throws IOException {
cm.shutdown();
}
});
}
return new BindPortCloseableHttpClient(
execChain,
connManagerCopy,
routePlannerCopy,
cookieSpecRegistryCopy,
authSchemeRegistryCopy,
defaultCookieStore,
defaultCredentialsProvider,
defaultRequestConfig != null ? defaultRequestConfig : RequestConfig.DEFAULT,
closeablesCopy);
}
}
修改了方法,和最後返回的值
final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", BindPortConnectSocketFactory.getSocketFactory())
.register("https", sslSocketFactoryCopy)
.build(),
null,
null,
null,
connTimeToLive,
connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS);
return new BindPortCloseableHttpClient(
execChain,
connManagerCopy,
routePlannerCopy,
cookieSpecRegistryCopy,
authSchemeRegistryCopy,
defaultCookieStore,
defaultCredentialsProvider,
defaultRequestConfig != null ? defaultRequestConfig : RequestConfig.DEFAULT,
closeablesCopy);
下面還有https請求的
我們看HttpClientBuilder類的第935行
if (connManagerCopy == null) {
LayeredConnectionSocketFactory sslSocketFactoryCopy = this.sslSocketFactory;
if (sslSocketFactoryCopy == null) {
final String[] supportedProtocols = systemProperties ? split(
System.getProperty("https.protocols")) : null;
final String[] supportedCipherSuites = systemProperties ? split(
System.getProperty("https.cipherSuites")) : null;
HostnameVerifier hostnameVerifierCopy = this.hostnameVerifier;
if (hostnameVerifierCopy == null) {
hostnameVerifierCopy = new DefaultHostnameVerifier(publicSuffixMatcherCopy);
}
if (sslContext != null) {
sslSocketFactoryCopy = new SSLConnectionSocketFactory(
sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
} else {
if (systemProperties) {
sslSocketFactoryCopy = new SSLConnectionSocketFactory(
(SSLSocketFactory) SSLSocketFactory.getDefault(),
supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
} else {
sslSocketFactoryCopy = new SSLConnectionSocketFactory(
SSLContexts.createDefault(),
hostnameVerifierCopy);
}
}
}
實體類就是SSLConnectionSocketFactory了,把這個類裏面的socket創建換掉,就可以啦
public class BindPortSSLConnrctSocketFactory implements LayeredConnectionSocketFactory {
public static final String TLS = "TLS";
public static final String SSL = "SSL";
public static final String SSLV2 = "SSLv2";
@Deprecated
public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER
= AllowAllHostnameVerifier.INSTANCE;
@Deprecated
public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
= BrowserCompatHostnameVerifier.INSTANCE;
@Deprecated
public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER
= StrictHostnameVerifier.INSTANCE;
private final Log log = LogFactory.getLog(getClass());
/**
* @since 4.4
*/
public static HostnameVerifier getDefaultHostnameVerifier() {
return new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault());
}
/**
* Obtains default SSL socket factory with an SSL context based on the standard JSSE
* trust material ({@code cacerts} file in the security properties directory).
* System properties are not taken into consideration.
*
* @return default SSL socket factory
*/
public static SSLConnectionSocketFactory getSocketFactory() throws SSLInitializationException {
return new SSLConnectionSocketFactory(SSLContexts.createDefault(), getDefaultHostnameVerifier());
}
private static String[] split(final String s) {
if (TextUtils.isBlank(s)) {
return null;
}
return s.split(" *, *");
}
/**
* Obtains default SSL socket factory with an SSL context based on system properties
* as described in
* <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html">
* Java™ Secure Socket Extension (JSSE) Reference Guide</a>.
*
* @return default system SSL socket factory
*/
public static SSLConnectionSocketFactory getSystemSocketFactory() throws SSLInitializationException {
return new SSLConnectionSocketFactory(
(javax.net.ssl.SSLSocketFactory) javax.net.ssl.SSLSocketFactory.getDefault(),
split(System.getProperty("https.protocols")),
split(System.getProperty("https.cipherSuites")),
getDefaultHostnameVerifier());
}
private final javax.net.ssl.SSLSocketFactory socketfactory;
private final HostnameVerifier hostnameVerifier;
private final String[] supportedProtocols;
private final String[] supportedCipherSuites;
public BindPortSSLConnrctSocketFactory(final SSLContext sslContext) {
this(sslContext, getDefaultHostnameVerifier());
}
/**
* @deprecated (4.4) Use {@link #BindPortSSLConnrctSocketFactory(javax.net.ssl.SSLContext,
* javax.net.ssl.HostnameVerifier)}
*/
@Deprecated
public BindPortSSLConnrctSocketFactory(
final SSLContext sslContext, final X509HostnameVerifier hostnameVerifier) {
this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
null, null, hostnameVerifier);
}
/**
* @deprecated (4.4) Use {@link #BindPortSSLConnrctSocketFactory(javax.net.ssl.SSLContext,
* String[], String[], javax.net.ssl.HostnameVerifier)}
*/
@Deprecated
public BindPortSSLConnrctSocketFactory(
final SSLContext sslContext,
final String[] supportedProtocols,
final String[] supportedCipherSuites,
final X509HostnameVerifier hostnameVerifier) {
this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
supportedProtocols, supportedCipherSuites, hostnameVerifier);
}
/**
* @deprecated (4.4) Use {@link #BindPortSSLConnrctSocketFactory(javax.net.ssl.SSLSocketFactory,
* javax.net.ssl.HostnameVerifier)}
*/
@Deprecated
public BindPortSSLConnrctSocketFactory(
final javax.net.ssl.SSLSocketFactory socketfactory,
final X509HostnameVerifier hostnameVerifier) {
this(socketfactory, null, null, hostnameVerifier);
}
/**
* @deprecated (4.4) Use {@link #BindPortSSLConnrctSocketFactory(javax.net.ssl.SSLSocketFactory,
* String[], String[], javax.net.ssl.HostnameVerifier)}
*/
@Deprecated
public BindPortSSLConnrctSocketFactory(
final javax.net.ssl.SSLSocketFactory socketfactory,
final String[] supportedProtocols,
final String[] supportedCipherSuites,
final X509HostnameVerifier hostnameVerifier) {
this(socketfactory, supportedProtocols, supportedCipherSuites, (HostnameVerifier) hostnameVerifier);
}
/**
* @since 4.4
*/
public BindPortSSLConnrctSocketFactory(
final SSLContext sslContext, final HostnameVerifier hostnameVerifier) {
this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
null, null, hostnameVerifier);
}
/**
* @since 4.4
*/
public BindPortSSLConnrctSocketFactory(
final SSLContext sslContext,
final String[] supportedProtocols,
final String[] supportedCipherSuites,
final HostnameVerifier hostnameVerifier) {
this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
supportedProtocols, supportedCipherSuites, hostnameVerifier);
}
/**
* @since 4.4
*/
public BindPortSSLConnrctSocketFactory(
final javax.net.ssl.SSLSocketFactory socketfactory,
final HostnameVerifier hostnameVerifier) {
this(socketfactory, null, null, hostnameVerifier);
}
/**
* @since 4.4
*/
public BindPortSSLConnrctSocketFactory(
final javax.net.ssl.SSLSocketFactory socketfactory,
final String[] supportedProtocols,
final String[] supportedCipherSuites,
final HostnameVerifier hostnameVerifier) {
this.socketfactory = Args.notNull(socketfactory, "SSL socket factory");
this.supportedProtocols = supportedProtocols;
this.supportedCipherSuites = supportedCipherSuites;
this.hostnameVerifier = hostnameVerifier != null ? hostnameVerifier : getDefaultHostnameVerifier();
}
/**
* Performs any custom initialization for a newly created SSLSocket
* (before the SSL handshake happens).
*
* The default implementation is a no-op, but could be overridden to, e.g.,
* call {@link javax.net.ssl.SSLSocket#setEnabledCipherSuites(String[])}.
* @throws IOException may be thrown if overridden
*/
protected void prepareSocket(final SSLSocket socket) throws IOException {
}
@Override
public Socket createSocket(final HttpContext context) throws IOException {
Socket socket = SocketFactory.getDefault().createSocket();
socket.bind(new InetSocketAddress(10012));
System.out.println("ssl-port = [" + socket.getLocalPort() + "]");
return socket;
}
@Override
public Socket connectSocket(
final int connectTimeout,
final Socket socket,
final HttpHost host,
final InetSocketAddress remoteAddress,
final InetSocketAddress localAddress,
final HttpContext context) throws IOException {
Args.notNull(host, "HTTP host");
Args.notNull(remoteAddress, "Remote address");
final Socket sock = socket != null ? socket : createSocket(context);
if (localAddress != null) {
sock.bind(localAddress);
}
try {
if (connectTimeout > 0 && sock.getSoTimeout() == 0) {
sock.setSoTimeout(connectTimeout);
}
if (this.log.isDebugEnabled()) {
this.log.debug("Connecting socket to " + remoteAddress + " with timeout " + connectTimeout);
}
sock.connect(remoteAddress, connectTimeout);
} catch (final IOException ex) {
try {
sock.close();
} catch (final IOException ignore) {
}
throw ex;
}
// Setup SSL layering if necessary
if (sock instanceof SSLSocket) {
final SSLSocket sslsock = (SSLSocket) sock;
this.log.debug("Starting handshake");
sslsock.startHandshake();
verifyHostname(sslsock, host.getHostName());
return sock;
} else {
return createLayeredSocket(sock, host.getHostName(), remoteAddress.getPort(), context);
}
}
@Override
public Socket createLayeredSocket(
final Socket socket,
final String target,
final int port,
final HttpContext context) throws IOException {
final SSLSocket sslsock = (SSLSocket) this.socketfactory.createSocket(
socket,
target,
port,
true);
if (supportedProtocols != null) {
sslsock.setEnabledProtocols(supportedProtocols);
} else {
// If supported protocols are not explicitly set, remove all SSL protocol versions
final String[] allProtocols = sslsock.getEnabledProtocols();
final List<String> enabledProtocols = new ArrayList<String>(allProtocols.length);
for (String protocol: allProtocols) {
if (!protocol.startsWith("SSL")) {
enabledProtocols.add(protocol);
}
}
if (!enabledProtocols.isEmpty()) {
sslsock.setEnabledProtocols(enabledProtocols.toArray(new String[enabledProtocols.size()]));
}
}
if (supportedCipherSuites != null) {
sslsock.setEnabledCipherSuites(supportedCipherSuites);
}
if (this.log.isDebugEnabled()) {
this.log.debug("Enabled protocols: " + Arrays.asList(sslsock.getEnabledProtocols()));
this.log.debug("Enabled cipher suites:" + Arrays.asList(sslsock.getEnabledCipherSuites()));
}
prepareSocket(sslsock);
this.log.debug("Starting handshake");
sslsock.startHandshake();
verifyHostname(sslsock, target);
return sslsock;
}
private void verifyHostname(final SSLSocket sslsock, final String hostname) throws IOException {
try {
SSLSession session = sslsock.getSession();
if (session == null) {
// In our experience this only happens under IBM 1.4.x when
// spurious (unrelated) certificates show up in the server'
// chain. Hopefully this will unearth the real problem:
final InputStream in = sslsock.getInputStream();
in.available();
// If ssl.getInputStream().available() didn't cause an
// exception, maybe at least now the session is available?
session = sslsock.getSession();
if (session == null) {
// If it's still null, probably a startHandshake() will
// unearth the real problem.
sslsock.startHandshake();
session = sslsock.getSession();
}
}
if (session == null) {
throw new SSLHandshakeException("SSL session not available");
}
if (this.log.isDebugEnabled()) {
this.log.debug("Secure session established");
this.log.debug(" negotiated protocol: " + session.getProtocol());
this.log.debug(" negotiated cipher suite: " + session.getCipherSuite());
try {
final Certificate[] certs = session.getPeerCertificates();
final X509Certificate x509 = (X509Certificate) certs[0];
final X500Principal peer = x509.getSubjectX500Principal();
this.log.debug(" peer principal: " + peer.toString());
final Collection<List<?>> altNames1 = x509.getSubjectAlternativeNames();
if (altNames1 != null) {
final List<String> altNames = new ArrayList<String>();
for (final List<?> aC : altNames1) {
if (!aC.isEmpty()) {
altNames.add((String) aC.get(1));
}
}
this.log.debug(" peer alternative names: " + altNames);
}
final X500Principal issuer = x509.getIssuerX500Principal();
this.log.debug(" issuer principal: " + issuer.toString());
final Collection<List<?>> altNames2 = x509.getIssuerAlternativeNames();
if (altNames2 != null) {
final List<String> altNames = new ArrayList<String>();
for (final List<?> aC : altNames2) {
if (!aC.isEmpty()) {
altNames.add((String) aC.get(1));
}
}
this.log.debug(" issuer alternative names: " + altNames);
}
} catch (Exception ignore) {
}
}
if (!this.hostnameVerifier.verify(hostname, session)) {
final Certificate[] certs = session.getPeerCertificates();
final X509Certificate x509 = (X509Certificate) certs[0];
final X500Principal x500Principal = x509.getSubjectX500Principal();
throw new SSLPeerUnverifiedException("Host name '" + hostname + "' does not match " +
"the certificate subject provided by the peer (" + x500Principal.toString() + ")");
}
// verifyHostName() didn't blowup - good!
} catch (final IOException iox) {
// close the socket before re-throwing the exception
try { sslsock.close(); } catch (final Exception x) { /*ignore*/ }
throw iox;
}
}
}
這樣,就可以啦
重新寫一個請求工具類
public class RestTemplateUtil2 {
public static RestTemplate restTemplate;
public static RestTemplate httpsRestTemplate;
private static int timeout = 5000;
private static String APPLICATION_JSON_UTF8 = "application/json;charset=UTF-8";
private static String APPLICATION_XML_UTF8 = "application/xml;charset=UTF-8";
public RestTemplateUtil2() throws Exception {
restTemplate = new RestTemplate();
org.apache.http.client.HttpClient httpClient = BindPortHttpClientBuilder.create().build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
factory.setReadTimeout(timeout);
factory.setConnectTimeout(timeout);
restTemplate.setRequestFactory(factory);
}
private static String[] split(final String s) {
if (TextUtils.isBlank(s)) {
return null;
}
return s.split(" *, *");
}
private <T> T post(String url, String param, String mediaType, Class<T> bodyType) {
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType(mediaType);
headers.setContentType(type);
return exchange(url, param, HttpMethod.POST, bodyType, headers);
}
public <T> T postJson(String url, String param, Class<T> bodyType) {
return post(url, param, APPLICATION_JSON_UTF8, bodyType);
}
public <T> T postXml(String url, String param, Class<T> bodyType) {
return post(url, param, APPLICATION_XML_UTF8, bodyType);
}
public <T> T get(String url, String param, Class<T> bodyType) {
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType(APPLICATION_JSON_UTF8);
headers.setContentType(type);
return exchange(url, param, HttpMethod.GET, bodyType, headers);
}
public <T> T put(String url, String data, Class<T> bodyType) {
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType(APPLICATION_JSON_UTF8);
headers.setContentType(type);
return exchange(url, data, HttpMethod.PUT, bodyType, headers);
}
public <T> T delete(String url, String data, Class<T> bodyType) {
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType(APPLICATION_JSON_UTF8);
headers.setContentType(type);
return exchange(url, data, HttpMethod.DELETE, bodyType, headers);
}
/**
* 發送/獲取 服務端數據(主要用於解決發送put,delete方法無返回值問題)
*
* @param url
* @param content
* @param method
* @param bodyType
* @param headers
* @param <T>
* @return
*/
private <T> T exchange(String url, String content, HttpMethod method, Class<T> bodyType, HttpHeaders headers) {
// 發送請求
HttpEntity<String> entity = new HttpEntity<>(content, headers);
ResponseEntity<T> resultEntity = restTemplate.exchange(url, method, entity, bodyType);
return resultEntity.getBody();
}
public <T> T httpsGet(String url, String param, Class<T> bodyType) {
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType(APPLICATION_JSON_UTF8);
headers.setContentType(type);
return exchangeHttps(url, param, HttpMethod.GET, bodyType, headers);
}
private <T> T exchangeHttps(String url, String content, HttpMethod method, Class<T> bodyType, HttpHeaders headers) {
// 發送請求
HttpEntity<String> entity = new HttpEntity<>(content, headers);
ResponseEntity<T> resultEntity = httpsRestTemplate.exchange(url, method, entity, bodyType);
return resultEntity.getBody();
}
public static void main(String[] args){
RestTemplateUtil2 restTemplateUtil2 = null;
try {
restTemplateUtil2 = new RestTemplateUtil2();
String url = "http://www.baidu.com";
// String s = restTemplateUtil2.get(url,null,String.class);
for (int i = 1 ; i <= 100;i++) {
String s = restTemplateUtil2.httpsGet(url, null, String.class);
System.out.println("s = [" + s + "]");
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("err = [" + e + "]");
}
}
}
運行一下,看看抓的包
這裏我單線程循環100次請求,都是10011,是沒有問題的,下篇再來說說多線程網絡請求綁定端口的問題