17

I have read some tutorials about implementing REST client in java web application that use SPRING to manage beans.

Every example I found, every time doing a REST request it creates new RestTemplate.

Normally web applications use singleton spring bean.

So I want to know when what is the best practice to use RestTemplate in Spring configures application ?
Use singleton RestTemplate ?
Create RestTemplate in every request. ?

Please advise and describe all situations.

Marci-man
  • 2,113
  • 3
  • 28
  • 76
Chamly Idunil
  • 1,848
  • 1
  • 18
  • 33

2 Answers2

18

One of the best ways to do this is to create a bean which would return a RestTemplate and then Autowire it in which ever class you need.

Something like this.

@Configuration
public class ProductServiceConfig {

    @Value("${product.username}")
    private String productServiceUsername;

    @Value("${product.password}")
    private String productServicePassword;

    @Bean(name = "restTemplateForProductService")
    public RestTemplate prepareRestTemplateForProductService() {

        BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(productServiceUsername, productServicePassword));

        RequestConfig.Builder requestBuilder = RequestConfig.custom();
        requestBuilder = requestBuilder.setConnectTimeout(1000);

        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
        httpClientBuilder.setDefaultRequestConfig(requestBuilder.build());
        CloseableHttpClient httpClient = httpClientBuilder.build();

        HttpComponentsClientHttpRequestFactory rf = new HttpComponentsClientHttpRequestFactory(httpClient);

        return new RestTemplate(rf);
    }
}

This way you can set different parameters that you want for your rest call, like timeouts or credentials etc. And when you want to use, you can just do

@Autowired
RestTemplate restTemplateForProductService;

restTemplateForProductService.......

Another advantage of this over using new RestTemplate () is if you have to call different services through REST, then you can define multiple beans (with different configuration) which returns RestTemplates and autowire it using the name

pvpkiran
  • 25,582
  • 8
  • 87
  • 134
  • Can we make the above RestTemplate bean creation generic, like suppose we have a bean with two different type of templates based on environment it should generate. So instead of creating rest template for ClientA and ClientB who have almost all configs same just the url different. Can we refactor somehow?https://stackoverflow.com/q/63117202/3560140 – NeverGiveUp161 Aug 03 '20 at 11:42
2

You should take one of the following approaches when using RestTemplate.

Static instance:

/**
 * Rest template client
 */
private static final RestTemplate TEMPLATE = new RestTemplate(new RestClientRequestFactory());


static{
    //Set your options here
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.featuresToEnable(SerializationFeature.WRITE_DATES_WITH_ZONE_ID);

    builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    builder.featuresToDisable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);

    MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter();
    jsonMessageConverter.setObjectMapper(builder.build());

    TEMPLATE.setMessageConverters(Arrays.asList(jsonMessageConverter));
}

Or delcare a Spring Bean in a @Configuration class:

@Bean
public RestTemplate restTemplate(){
    RestTemplate template = new RestTemplate(new RestClientRequestFactory())
            //customize
    return template;
}

If you look at the RestTemplate class the you want to avoid hitting the default Constructor too many times:

public RestTemplate() {
    this.messageConverters = new ArrayList();
    this.errorHandler = new DefaultResponseErrorHandler();
    this.uriTemplateHandler = new DefaultUriTemplateHandler();
    this.headersExtractor = new RestTemplate.HeadersExtractor();
    this.messageConverters.add(new ByteArrayHttpMessageConverter());
    this.messageConverters.add(new StringHttpMessageConverter());
    this.messageConverters.add(new ResourceHttpMessageConverter());
    this.messageConverters.add(new SourceHttpMessageConverter());
    this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
    if (romePresent) {
        this.messageConverters.add(new AtomFeedHttpMessageConverter());
        this.messageConverters.add(new RssChannelHttpMessageConverter());
    }

    if (jackson2XmlPresent) {
        this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
    } else if (jaxb2Present) {
        this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
    }

    if (jackson2Present) {
        this.messageConverters.add(new MappingJackson2HttpMessageConverter());
    } else if (gsonPresent) {
        this.messageConverters.add(new GsonHttpMessageConverter());
    }

}
Johnny.Minty
  • 143
  • 1
  • 10
  • because of huge requests amount, I got "Too many open file" on my app. A problem in many convertors loading. Can I reuse one list of converters for many Templates? Is it thread safe? – demon101 Jan 09 '18 at 20:42
  • 1
    Yes, RestTemplate is thread safe https://spring.io/blog/2009/03/27/rest-in-spring-3-resttemplate – demon101 Jan 10 '18 at 21:09