最近公司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,是没有问题的,下篇再来说说多线程网络请求绑定端口的问题