使用 spring RestTemplate 的 rest 客户端最佳实践

2022-09-03 06:31:35

我已经阅读了一些关于在java Web应用程序中实现REST客户端的教程,这些应用程序使用SPRING来管理bean。

我发现的每个示例,每次执行 REST 请求时,它都会创建新的 RestTemplate。

通常,Web 应用程序使用单例弹簧豆。

所以我想知道什么时候在Spring中使用RestTemplate配置应用程序的最佳实践是什么?
使用单例 RestTemplate ?
在每个请求中创建 RestTemplate。?

请告知并描述所有情况。


答案 1

最好的方法之一是创建一个bean,它将返回一个RestTemplate,然后将其自动连接到您需要的任何类中。

像这样的东西。

@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);
    }
}

通过这种方式,您可以为 rest 调用设置所需的不同参数,例如超时或凭据等。当你想使用时,你可以做

@Autowired
RestTemplate restTemplateForProductService;

restTemplateForProductService.......

与使用相比,这样做的另一个优点是,如果您必须通过REST调用不同的服务,那么您可以定义多个bean(具有不同的配置),该bean返回RestTemplates并使用名称自动连接它。new RestTemplate ()


答案 2

使用 RestTemplate 时,应采用以下方法之一。

静态实例:

/**
 * 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));
}

或者在@Configuration课上德尔卡一个春豆:

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

如果您查看 RestTemplate 类,您希望避免多次命中默认构造函数:

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

}