As I know the RestTemplateBuilder
is some kind of factory for RestTemplate
. I have a few questions about using it:
Very often in examples there is something like this in @Configuration
class:
@Bean
public RestTemplate getRestClient() {
RestTemplate restClient = new RestTemplate();
...
return restClient;
}
Shouldn't RestTemplate
be instantiated per @Service
class ? If so, how to customize it ?
Spring reference says that RestTemplateBuilder
should be customized via RestTemplateCustomizer
. How to manage many URI's from many IP addresses with one builder ?
How to add BasicAuthentication
globaly to all RestTemplates
via RestTemplateBuilder
, and is it a good practice?
Thanks for help.
UPDATE:
My application calls rest services from many servers at different IP's and urls - so logically for me is the situation when I have many RestTemplates
.
I'm trying to have a factory (RestTemplateBuilder
) per server - let's say servers A, B, C. I know how to add a basic authentication. But what for example when I want a basic authentication for server A but not for server B ?
I think about having one RestTemplateBuilder
per server. I don't want to do this manually - I would prefer to use Spring mechanisms.
Any help ?
public class RestTemplateBuilder extends Object. Builder that can be used to configure and create a RestTemplate . Provides convenience methods to register converters , error handlers and UriTemplateHandlers .
Rest Template is used to create applications that consume RESTful Web Services. You can use the exchange() method to consume the web services for all HTTP methods. The code given below shows how to create Bean for Rest Template to auto wiring the Rest Template object.
RestTemplate uses Java Servlet API and is therefore synchronous and blocking. Conversely, WebClient is asynchronous and will not block the executing thread while waiting for the response to come back. The notification will be produced only when the response is ready. RestTemplate will still be used.
Creating a RestTemplate Bean In any Controller, we can directly instantiate a local instance of a RestTemplate by simply instantiating the class into an object: private RestTemplate restTemplate = new RestTemplate();
I've set up my config like this:
@Bean
public RestTemplateCustomizer restTemplateCustomizer() {
return restTemplate -> {
restTemplate.setRequestFactory(clientHttpRequestFactory());
};
}
@Bean
public ClientHttpRequestFactory clientHttpRequestFactory() {
SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(connectionTimeoutMs);
clientHttpRequestFactory.setReadTimeout(connectionTimeoutMs);
clientHttpRequestFactory.setBufferRequestBody(false);
return clientHttpRequestFactory;
}
Whenever Spring injects a RestTemplateBuilder, it will configure it using this RestTemplateCustomizer to use the ClientHttpRequestFactory. You may need to do some different customizations, or perhaps none in which case don't declare the bean.
To add the authentication header, you will need to know the user name and password, which you probably won't know until run-time. So I've created an Authenticator bean:
@Component
public class Authenticator {
@Autowired
private RestTemplateBuilder restTemplateBuilder;
public void withAuthenticationHeader(String username, String password, Consumer<RestTemplate> doAuthenticated) {
RestTemplate restTemplate =
restTemplateBuilder
.basicAuthorization(username, password)
.build();
try {
doAuthenticated.accept(restTemplate);
} catch (HttpClientErrorException exception) {
// handle the exception
}
}
}
This allows me to handle authentication failures in a standard way for all requests, which is what I need in my application.
It is injected into other beans and used like so:
@Autowired
private Authenticator authenticator;
public void transmit() {
authenticator.withAuthenticationHeader(username, password, restTemplate ->
restTemplate.postForLocation(url, request));
}
So you'd use the Authenticator rather than using the RestTemple directly. I couldn't find any standard patterns for this sort of thing, but this seems to work.
No, you don't need to, typically you will have on rest template instance, and you would pass different url, and request parameters accordingly every time.
String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", String.class, vars);
Foo foo = restTemplate.getForObject(fooResourceUrl + "/1", Foo.class);
A descriptive example from spring doc, you can add as many customizers to the builder
public class ProxyCustomizer implements RestTemplateCustomizer {
@Override
public void customize(RestTemplate restTemplate) {
HttpHost proxy = new HttpHost("proxy.example.com");
HttpClient httpClient = HttpClientBuilder.create()
.setRoutePlanner(new DefaultProxyRoutePlanner(proxy) {
@Override
public HttpHost determineProxy(HttpHost target,
HttpRequest request, HttpContext context)
throws HttpException {
if (target.getHostName().equals("192.168.0.5")) {
return null;
}
return super.determineProxy(target, request, context);
}
}).build();
restTemplate.setRequestFactory(
new HttpComponentsClientHttpRequestFactory(httpClient));
}
}
Any RestTemplateCustomizer beans will be automatically added to the auto-configured RestTemplateBuilder. Furthermore, a new RestTemplateBuilder with additional customizers can be created by calling additionalCustomizers(RestTemplateCustomizer…)
@Bean
public RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder()
.rootUri(rootUri)
.basicAuthorization(username, password);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With