001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.http.client; 018 019import java.io.Closeable; 020import java.io.IOException; 021import java.net.URI; 022 023import org.apache.http.client.HttpClient; 024import org.apache.http.client.config.RequestConfig; 025import org.apache.http.client.methods.Configurable; 026import org.apache.http.client.methods.HttpUriRequest; 027import org.apache.http.client.protocol.HttpClientContext; 028import org.apache.http.impl.client.CloseableHttpClient; 029import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; 030import org.apache.http.impl.nio.client.HttpAsyncClients; 031import org.apache.http.nio.client.HttpAsyncClient; 032import org.apache.http.protocol.HttpContext; 033 034import org.springframework.beans.factory.InitializingBean; 035import org.springframework.http.HttpMethod; 036import org.springframework.util.Assert; 037 038/** 039 * Asynchronous extension of the {@link HttpComponentsClientHttpRequestFactory}. Uses 040 * <a href="https://hc.apache.org/httpcomponents-asyncclient-dev/">Apache HttpComponents 041 * HttpAsyncClient 4.0</a> to create requests. 042 * 043 * @author Arjen Poutsma 044 * @author Stephane Nicoll 045 * @since 4.0 046 * @see HttpAsyncClient 047 */ 048public class HttpComponentsAsyncClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory 049 implements AsyncClientHttpRequestFactory, InitializingBean { 050 051 private HttpAsyncClient asyncClient; 052 053 054 /** 055 * Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory} 056 * with a default {@link HttpAsyncClient} and {@link HttpClient}. 057 */ 058 public HttpComponentsAsyncClientHttpRequestFactory() { 059 super(); 060 this.asyncClient = HttpAsyncClients.createSystem(); 061 } 062 063 /** 064 * Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory} 065 * with the given {@link HttpAsyncClient} instance and a default {@link HttpClient}. 066 * @param asyncClient the HttpAsyncClient instance to use for this request factory 067 * @since 4.3.10 068 */ 069 public HttpComponentsAsyncClientHttpRequestFactory(HttpAsyncClient asyncClient) { 070 super(); 071 setAsyncClient(asyncClient); 072 } 073 074 /** 075 * Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory} 076 * with the given {@link CloseableHttpAsyncClient} instance and a default {@link HttpClient}. 077 * @param asyncClient the CloseableHttpAsyncClient instance to use for this request factory 078 */ 079 public HttpComponentsAsyncClientHttpRequestFactory(CloseableHttpAsyncClient asyncClient) { 080 super(); 081 setAsyncClient(asyncClient); 082 } 083 084 /** 085 * Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory} 086 * with the given {@link HttpClient} and {@link HttpAsyncClient} instances. 087 * @param httpClient the HttpClient instance to use for this request factory 088 * @param asyncClient the HttpAsyncClient instance to use for this request factory 089 * @since 4.3.10 090 */ 091 public HttpComponentsAsyncClientHttpRequestFactory(HttpClient httpClient, HttpAsyncClient asyncClient) { 092 super(httpClient); 093 setAsyncClient(asyncClient); 094 } 095 096 /** 097 * Create a new instance of the {@code HttpComponentsAsyncClientHttpRequestFactory} 098 * with the given {@link CloseableHttpClient} and {@link CloseableHttpAsyncClient} instances. 099 * @param httpClient the CloseableHttpClient instance to use for this request factory 100 * @param asyncClient the CloseableHttpAsyncClient instance to use for this request factory 101 */ 102 public HttpComponentsAsyncClientHttpRequestFactory( 103 CloseableHttpClient httpClient, CloseableHttpAsyncClient asyncClient) { 104 105 super(httpClient); 106 setAsyncClient(asyncClient); 107 } 108 109 110 /** 111 * Set the {@code HttpAsyncClient} used for 112 * {@linkplain #createAsyncRequest(URI, HttpMethod) synchronous execution}. 113 * @since 4.3.10 114 * @see #setHttpClient(HttpClient) 115 */ 116 public void setAsyncClient(HttpAsyncClient asyncClient) { 117 Assert.notNull(asyncClient, "HttpAsyncClient must not be null"); 118 this.asyncClient = asyncClient; 119 } 120 121 /** 122 * Return the {@code HttpAsyncClient} used for 123 * {@linkplain #createAsyncRequest(URI, HttpMethod) synchronous execution}. 124 * @since 4.3.10 125 * @see #getHttpClient() 126 */ 127 public HttpAsyncClient getAsyncClient() { 128 return this.asyncClient; 129 } 130 131 /** 132 * Set the {@code CloseableHttpAsyncClient} used for 133 * {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}. 134 * @deprecated as of 4.3.10, in favor of {@link #setAsyncClient(HttpAsyncClient)} 135 */ 136 @Deprecated 137 public void setHttpAsyncClient(CloseableHttpAsyncClient asyncClient) { 138 this.asyncClient = asyncClient; 139 } 140 141 /** 142 * Return the {@code CloseableHttpAsyncClient} used for 143 * {@linkplain #createAsyncRequest(URI, HttpMethod) asynchronous execution}. 144 * @deprecated as of 4.3.10, in favor of {@link #getAsyncClient()} 145 */ 146 @Deprecated 147 public CloseableHttpAsyncClient getHttpAsyncClient() { 148 Assert.state(this.asyncClient == null || this.asyncClient instanceof CloseableHttpAsyncClient, 149 "No CloseableHttpAsyncClient - use getAsyncClient() instead"); 150 return (CloseableHttpAsyncClient) this.asyncClient; 151 } 152 153 154 @Override 155 public void afterPropertiesSet() { 156 startAsyncClient(); 157 } 158 159 private void startAsyncClient() { 160 HttpAsyncClient asyncClient = getAsyncClient(); 161 if (asyncClient instanceof CloseableHttpAsyncClient) { 162 CloseableHttpAsyncClient closeableAsyncClient = (CloseableHttpAsyncClient) asyncClient; 163 if (!closeableAsyncClient.isRunning()) { 164 closeableAsyncClient.start(); 165 } 166 } 167 } 168 169 @Override 170 public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException { 171 startAsyncClient(); 172 173 HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri); 174 postProcessHttpRequest(httpRequest); 175 HttpContext context = createHttpContext(httpMethod, uri); 176 if (context == null) { 177 context = HttpClientContext.create(); 178 } 179 180 // Request configuration not set in the context 181 if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) { 182 // Use request configuration given by the user, when available 183 RequestConfig config = null; 184 if (httpRequest instanceof Configurable) { 185 config = ((Configurable) httpRequest).getConfig(); 186 } 187 if (config == null) { 188 config = createRequestConfig(getAsyncClient()); 189 } 190 if (config != null) { 191 context.setAttribute(HttpClientContext.REQUEST_CONFIG, config); 192 } 193 } 194 195 return new HttpComponentsAsyncClientHttpRequest(getAsyncClient(), httpRequest, context); 196 } 197 198 @Override 199 public void destroy() throws Exception { 200 try { 201 super.destroy(); 202 } 203 finally { 204 HttpAsyncClient asyncClient = getAsyncClient(); 205 if (asyncClient instanceof Closeable) { 206 ((Closeable) asyncClient).close(); 207 } 208 } 209 } 210 211}