聊聊HttpComponentsHttpInvokerRequestExecutor

本文主要研究一下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;

	@Nullable
	private 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 merge
			return 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)。

相关推荐
之歆3 分钟前
RGA-检索增强生成(Retrieval-augmented Generation)
java·spring
Chan165 分钟前
场景题:如何设计一个分布式ID
java·开发语言·spring boot·java-ee·intellij-idea
@TangXin9 分钟前
Jenkins-Pipeline语法示例
java·servlet·jenkins
Geoking.20 分钟前
【设计模式】组合模式(Composite)详解
java·设计模式·组合模式
怦怦蓝22 分钟前
IDEA 项目打印日志全攻略:从基础使用到高级配置
java·开发语言·debug
Stream_Silver22 分钟前
高效并行测试:在IDEA中同时运行多个参数化测试配置(idea2019如何在同一个项目运行多次)
java·ide·intellij-idea
BD_Marathon22 分钟前
搭建MyBatis框架之创建mapper接口(四)
java·前端
kaico201826 分钟前
ConcurrentHashMap源码分析
java
虫小宝28 分钟前
企业微信API接口对接中Java后端的模拟测试(Mock)与单元测试实战技巧
java·单元测试·企业微信
Tim_Van30 分钟前
彻底解决:80 端口 GET/POST 正常,PUT 却报 ERR_CONNECTION_RESET?
java·vue.js·spring boot·ruoyi·若依