Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring boot - rest template and rest template builder

As I know the RestTemplateBuilder is some kind of factory for RestTemplate. I have a few questions about using it:

  1. 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 ?

  2. Spring reference says that RestTemplateBuilder should be customized via RestTemplateCustomizer. How to manage many URI's from many IP addresses with one builder ?

  3. 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 ?

like image 923
javovy Avatar asked Oct 10 '16 11:10

javovy


People also ask

What is rest template builder?

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 .

What is rest template in Spring boot?

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.

What is the difference between RestTemplate and WebClient?

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.

How do you instantiate RestTemplate in Spring boot?

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();


2 Answers

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.

like image 152
whistling_marmot Avatar answered Nov 15 '22 12:11

whistling_marmot


  1. 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);
    
  2. 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);
}
like image 35
kuhajeyan Avatar answered Nov 15 '22 12:11

kuhajeyan