Skip to content

Deprecate+Remove ability to provide a custom ClientHttpRequestFactory instance in RestTemplateBuilder #11255

Closed
@tvahrst

Description

@tvahrst

Problem

When ClientHttpRequestFactory isn't explicitly set, RestTemplateBuilder invokes detectRequestFactory() internally for every new RestTemplate. So every RestTemplate gets it's own 'prototype' ClientHttpRequestFactory.

On the other hand, when ClientHttpRequestFactory is explicitly set in RestTemplateBuilder, all subsequent build RestTemplates get the same 'singleton' ClientHttpRequestFactory.

During ResttemplateBuilder.build() method, the current ClientHttpRequestFactory becomes customized with timout values (connection-timeout and read-timeout). This leads to problems when multiple RestTemplates with different timeout values are created.

We have a Spring-Boot application that provides a RestTemplateBuilder bean which is already provided with a HttpComponentsHttpRequestFactory. Two service beans uses the RestTemplateBuilder to create a custom RestTemplate with different connection-timouts:

public class TestResttemplateBuilderTimeouts {
	private static Logger logger = LoggerFactory.getLogger(TestResttemplateBuilderTimeouts.class);

	@Test
	public void test1(){
		// globally prepared ResttemplateBuilder:
		HttpComponentsClientHttpRequestFactory f = new HttpComponentsClientHttpRequestFactory();
		RestTemplateBuilder builder = new RestTemplateBuilder().requestFactory(f);

		// in service bean 1:
		RestTemplate rt1 = builder.setConnectTimeout(10000).build();

		// in service bean 2
		RestTemplate rt2 = builder.setConnectTimeout(1000).build();


		// service bean 1 uses RestTemplate expecting connectionTime 10 Secs.  
		// but Connection-Timeout is only 1 Sec.
		try {
			logger.debug("start ...");
			String s = rt1.getForObject("http://www.google.com:81", String.class);
		}finally {
			logger.debug("stop ...");
		}
	}
}

Workaround

Our current Workaround: we do not set HttpComponentsHttpRequestFactory explicitly but let RestTemplateBuilder detect this factory. For customizing (i.e. setting max-connections und max-connections-per-route) we use the systemproperties approach of the httpcomponents httpclient.

Possible Solution (breaking the api in spring-web)

As far as I can see, all supported http implementations (httpcommons, netty, okhttp, okhttp3, SimpleClientHttpRequestFactory) allow a per request setting of connection- and read-timeouts. So a solution would be not to inject these timeouts into the ClientHttpRequestFactory but hold it as 'RequestSettings' in the RestTemplateBuilder and give them to every new created RestTemplate.

The RestTemplate in turn has to provide these settings as additional method-parameter to ClientHttpRequestFactory.createRequest(). This will however break the api of ClientHttpRequestFactory...

public interface ClientHttpRequestFactory {

	/**
	 * Create a new {@link ClientHttpRequest} for the specified URI and HTTP method.
	 * <p>The returned request can be written to, and then executed by calling
	 * {@link ClientHttpRequest#execute()}.
	 * @param uri the URI to create a request for
	 * @param httpMethod the HTTP method to execute
         * @param requestSettings Request-Settings, containing for instance connection- and read-timeouts
	 * @return the created request
	 * @throws IOException in case of I/O errors
	 */
	ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, RequestSettings requestSettings) throws IOException;

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions