序
本文主要研究一下HttpComponentsHttpInvokerRequestExecutor
HttpComponentsHttpInvokerRequestExecutor
org/springframework/remoting/httpinvoker/HttpComponentsHttpInvokerRequestExecutor.java
public class HttpComponentsHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {private static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 100;private static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 5;private static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = (60 * 1000);private HttpClient httpClient;@Nullableprivate RequestConfig requestConfig;/*** Create a new instance of the HttpComponentsHttpInvokerRequestExecutor with a default* {@link HttpClient} that uses a default {@code org.apache.http.impl.conn.PoolingClientConnectionManager}.*/public HttpComponentsHttpInvokerRequestExecutor() {this(createDefaultHttpClient(), RequestConfig.custom().setSocketTimeout(DEFAULT_READ_TIMEOUT_MILLISECONDS).build());}private static HttpClient createDefaultHttpClient() {Registry<ConnectionSocketFactory> schemeRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", SSLConnectionSocketFactory.getSocketFactory()).build();PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(schemeRegistry);connectionManager.setMaxTotal(DEFAULT_MAX_TOTAL_CONNECTIONS);connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE);return HttpClientBuilder.create().setConnectionManager(connectionManager).build();}//......
}
HttpComponentsHttpInvokerRequestExecutor继承了AbstractHttpInvokerRequestExecutor,其构造器提供了createDefaultHttpClient方法,默认注册了http及https的socketFactory,然后创建了PoolingHttpClientConnectionManager,默认maxTotal为100,defaultMaxPerRoute为5,其requestConfig默认设置了socketTimeout为60s
doExecuteRequest
protected RemoteInvocationResult doExecuteRequest(HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)throws IOException, ClassNotFoundException {HttpPost postMethod = createHttpPost(config);setRequestBody(config, postMethod, baos);try {HttpResponse response = executeHttpPost(config, getHttpClient(), postMethod);validateResponse(config, response);InputStream responseBody = getResponseBody(config, response);return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());}finally {postMethod.releaseConnection();}}
HttpComponentsHttpInvokerRequestExecutor实现了AbstractHttpInvokerRequestExecutor定义的doExecuteRequest方法,执行createHttpPost创建postMethod,然后设置requestBody,之后设置setRequestBody,接着执行executeHttpPost,验证response,读取responseBody,最后在finally里头执行postMethod.releaseConnection()
createHttpPost
protected HttpPost createHttpPost(HttpInvokerClientConfiguration config) throws IOException {HttpPost httpPost = new HttpPost(config.getServiceUrl());RequestConfig requestConfig = createRequestConfig(config);if (requestConfig != null) {httpPost.setConfig(requestConfig);}LocaleContext localeContext = LocaleContextHolder.getLocaleContext();if (localeContext != null) {Locale locale = localeContext.getLocale();if (locale != null) {httpPost.addHeader(HTTP_HEADER_ACCEPT_LANGUAGE, locale.toLanguageTag());}}if (isAcceptGzipEncoding()) {httpPost.addHeader(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);}return httpPost;}protected RequestConfig createRequestConfig(HttpInvokerClientConfiguration config) {HttpClient client = getHttpClient();if (client instanceof Configurable) {RequestConfig clientRequestConfig = ((Configurable) client).getConfig();return mergeRequestConfig(clientRequestConfig);}return this.requestConfig;}private RequestConfig mergeRequestConfig(RequestConfig defaultRequestConfig) {if (this.requestConfig == null) { // nothing to mergereturn defaultRequestConfig;}RequestConfig.Builder builder = RequestConfig.copy(defaultRequestConfig);int connectTimeout = this.requestConfig.getConnectTimeout();if (connectTimeout >= 0) {builder.setConnectTimeout(connectTimeout);}int connectionRequestTimeout = this.requestConfig.getConnectionRequestTimeout();if (connectionRequestTimeout >= 0) {builder.setConnectionRequestTimeout(connectionRequestTimeout);}int socketTimeout = this.requestConfig.getSocketTimeout();if (socketTimeout >= 0) {builder.setSocketTimeout(socketTimeout);}return builder.build();}
createHttpPost先是创建HttpPost,然后设置requestConfig,接着设置locale及gzipEncoding
setRequestBody
protected void setRequestBody(HttpInvokerClientConfiguration config, HttpPost httpPost, ByteArrayOutputStream baos)throws IOException {ByteArrayEntity entity = new ByteArrayEntity(baos.toByteArray());entity.setContentType(getContentType());httpPost.setEntity(entity);}
setRequestBody方法这里创建ByteArrayEntity,设置contentType,然后赋值给httpPost
executeHttpPost
protected HttpResponse executeHttpPost(HttpInvokerClientConfiguration config, HttpClient httpClient, HttpPost httpPost)throws IOException {return httpClient.execute(httpPost);}
executeHttpPost直接通过httpClient.execute方法执行post请求
getResponseBody
protected InputStream getResponseBody(HttpInvokerClientConfiguration config, HttpResponse httpResponse)throws IOException {if (isGzipResponse(httpResponse)) {return new GZIPInputStream(httpResponse.getEntity().getContent());}else {return httpResponse.getEntity().getContent();}}protected boolean isGzipResponse(HttpResponse httpResponse) {Header encodingHeader = httpResponse.getFirstHeader(HTTP_HEADER_CONTENT_ENCODING);return (encodingHeader != null && encodingHeader.getValue() != null &&encodingHeader.getValue().toLowerCase().contains(ENCODING_GZIP));}
getResponseBody方法会先判断是否是gzip,是的话创建GZIPInputStream,否则直接取httpResponse.getEntity().getContent()
小结
HttpComponentsHttpInvokerRequestExecutor是org.springframework.remoting.httpinvoker包里头的,它继承了继承了AbstractHttpInvokerRequestExecutor,演示了httpclient的基本配置(默认maxTotal为100,defaultMaxPerRoute为5,其requestConfig默认设置了socketTimeout为60s
)及其使用(创建request、设置entity、执行请求、解析response
)。