美文网首页
聊聊HttpComponentsHttpInvokerReque

聊聊HttpComponentsHttpInvokerReque

作者: go4it | 来源:发表于2023-10-02 09:16 被阅读0次

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

    相关文章

      网友评论

          本文标题:聊聊HttpComponentsHttpInvokerReque

          本文链接:https://www.haomeiwen.com/subject/fxrsbdtx.html