简体   繁体   English

如何为 Spring 中的每个客户端配置和构建自定义 RestTemplate?

[英]How to configure and build a custom RestTemplate for each client in Spring?

I am using Spring RestTemplate for executing HTTP request from my application.我正在使用 Spring RestTemplate 执行来自我的应用程序的 HTTP 请求。 There are several services we need to call, some on the internet and some on intranet, some fast and some slow.我们需要调用几个服务,一些在 Internet 上,一些在 Intranet 上,一些快速而一些慢。 I have been instructed to configure custom settings for each service, basically, connection timeout, read timeout.我被指示为每个服务配置自定义设置,基本上是连接超时、读取超时。

These setting will be extremely specific for example, the services hosted on intranet would have a timeout of ~2-5s while they provide an SLA of 1000ms for 99.9% of requests.这些设置将非常具体,例如,托管在 Intranet 上的服务将有约 2-5 秒的超时,而它们为 99.9% 的请求提供 1000 毫秒的 SLA。 While the other third party services with ~10-60s.而其他第三方服务大约 10-60 秒。

As these parameters can be set in the factory for the template only, i am creating a number of beans with different factories differing in timeouts only.由于只能在工厂中为模板设置这些参数,因此我正在创建许多具有不同工厂的 bean,它们仅在超时方面有所不同。 Something like this:像这样的东西:

@Bean
RestTemplate restTemplate() {
    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
    factory.setReadTimeout(20000);
    factory.setConnectTimeout(5000);
    RestTemplate restTemplate = new RestTemplate(factory);
}

I am afraid this will create a maintenance nightmare eventually.恐怕这最终会造成维护噩梦。 Can it be solved in a better ways?能否以更好的方式解决?

PS: The application is a monolith calling various services. PS:该应用程序是一个调用各种服务的单体。

You will have to create multiple RestTemplates and assign timeouts, connection pool size.您将不得不创建多个 RestTemplates 并分配超时、连接池大小。 Connection pool will improve the performance drastically连接池将大大提高性能

I have hard-coded the connection properties, you can pick it from application.properties file我已经对连接属性进行了硬编码,您可以从 application.properties 文件中选择它

@Configuration
class RestTemplateConfigs {
    @Bean
    public HttpClient httpClient() {
        return HttpClientBuilder.create()
                .setMaxConnPerRoute(200)
                .setMaxConnTotal(50)
                .setConnectionTimeToLive(10L, TimeUnit.SECONDS)
                .build();
    }

    @Bean(name = "restTemplate1")
    RestTemplate restTemplate() {
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient());
        RestTemplate restTemplate = new RestTemplate(factory);
        return restTemplate;
    }
}

You can create multiple RestTemplates and Autowire it using Qualifier name.您可以创建多个 RestTemplates 并使用限定符名称对其进行自动装配。

Disclaimer : my answer suggests to work with another Http client than Rest Template - If you must use Rest template my answer would be irrelevant.免责声明:我的回答建议使用另一个 Http 客户端而不是 Rest 模板 - 如果您必须使用 Rest 模板,我的回答将是无关紧要的。

I dealt with a similar design issue and here is what I did.我处理了一个类似的设计问题,这就是我所做的。 I wrote my own HttpClient class.我编写了自己的 HttpClient class。 It is much simpler in use then most known Http clients.它使用起来比大多数已知的 Http 客户端简单得多。 This class could be used on its own or (and this is relevant for your case) it could be used as a parent class for a group of classes (implementing the same interface) where each class will be an Http client for specific Rest Service. This class could be used on its own or (and this is relevant for your case) it could be used as a parent class for a group of classes (implementing the same interface) where each class will be an Http client for specific Rest Service. On this class you can pre-set the target URL and all the parameters (such as read and connection timeouts etc).在此 class 上,您可以预先设置目标 URL 和所有参数(例如读取和连接超时等)。 Once this class is preset, all you need to do is to invoke sendHttpRequestMethod().预设此 class 后,您需要做的就是调用 sendHttpRequestMethod()。 Just to expand a bit - lets say you have a User Rest service with CRUD API implemented by particular URL calls with different HTTP methods and may be different URLs. Just to expand a bit - lets say you have a User Rest service with CRUD API implemented by particular URL calls with different HTTP methods and may be different URLs. (say in addition to create (POST) update (PUT) read (GET) and delete (DELETE) methods that are located at HTTP://www.myserver.com:8083/user say you will also have methods activate and deactivate (say both GET) at URLs HTTP://www.myserver.com:8083/user/activate/ and HTTP://www.myserver.com:8083/user/deactivate. So, in this case, your Http client will set all required timeouts and other configurations and it will also have pre-set target URL HTTP://www.myserver.com:8083/user. and it will have six methods as mentioned above, where each one will simply invoke the parent class method sendHttpRequest(). Of course, for activate and deactivate methods you will need (比如说除了创建(POST)更新(PUT)读取(GET)和删除(DELETE)方法之外,这些方法位于 HTTP://www.myserver.com:8083/user 说您还将有方法激活和停用( say both GET) at URLs HTTP://www.myserver.com:8083/user/activate/ and HTTP://www.myserver.com:8083/user/deactivate. So, in this case, your Http client will set all required timeouts and other configurations and it will also have pre-set target URL HTTP://www.myserver.com:8083/user. and it will have six methods as mentioned above, where each one will simply invoke the parent class method sendHttpRequest()。当然,对于激活和停用方法,您将需要to append "activate" and "deactivate" suffixes for pre-set base URL.到 append “激活”和“停用”预设基础 URL 的后缀。 So, for each REST service, you can create a dedicated Http client with very minimal effort since the base class already does most of the job.因此,对于每个 REST 服务,您可以轻松地创建一个专用的 Http 客户端,因为基础 class 已经完成了大部分工作。 In addition to it, I wrote a self-populating factory for any group of classes that implement the same interface.除此之外,我还为任何一组实现相同接口的类编写了一个自填充工厂。 With that factory, all you will have to do is to write your additional Http client and the factory will detect it and will make it available on its own by predefined name or by the name of the class (based on your choice).使用该工厂,您所要做的就是编写额外的 Http 客户端,工厂将检测到它,并将通过预定义的名称或 class 的名称(根据您的选择)自行提供。 All this worked so well for me, that I packaged it into Open Source library called MgntUtils and published it on Maven and Github (with source code and Javadoc. JavaDoc is available here ).这一切对我来说都很好,我将它打包到名为 MgntUtils 的开源库中,并在MavenGithub上发布(带有源代码和 Javadoc。JavaDoc 可在此处获得)。 A detailed explanation on the Self-populating factory can be seen in Javadoc here .有关自填充工厂的详细说明,请参见此处的 Javadoc。 Also, the general article about the library can be found here and specific article about the idea and the implementation of self-populating Factory can be found here .此外,关于库的一般文章可以在这里找到,关于自填充工厂的想法和实现的具体文章可以在这里找到。 Package com.mgnt.lifecycle.management.example in the source code contains a working example.源代码中的 Package com.mgnt.lifecycle.management.example 包含一个工作示例。 I hope this helps.我希望这有帮助。

Using parameterized construction of the RestTemplate bean solved my problem.使用 RestTemplate bean 的参数化构造解决了我的问题。 The bean is now configured as: bean 现在配置为:

    @Bean
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    public RestTemplate getRestTemplate(String configParam){
        int connectionTimeout; //get from config using configParam
        int readTimeout;  //get from config using configParam
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setConnectTimeout(connectionTimeout);
        factory.setReadTimeout(readTimeout);

        return new RestTemplate(factory);
    }

Instead of @Autowiring this field, it can be injected in may be @PostConstruct method like depicted below.除了@Autowiring 这个字段,它可以被注入可能是@PostConstruct 方法,如下图所示。 The dependent bean can do following:依赖 bean 可以执行以下操作:

@Autowire
BeanFactory beanFactory;

RestTemplate restTemplate;

@PostConstruct
public void init(){
    restTemplate = beanFactory.getBean(RestTemplate.class, configParam);
}

Here you can have your bean with custom settings injected in restTemplate .在这里,您可以将带有自定义设置的 bean 注入到restTemplate中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用spring-cloud-config-client时如何配置自定义RestTemplate? - How to configure a custom RestTemplate when using spring-cloud-config-client? 如何为客户端和服务器配置Spring Boot RestTemplate代理 - How to configure spring boot resttemplate proxy for client and server 如何将Spring Cache Redis与自定义RestTemplate一起使用? - How to use Spring Cache Redis with a custom RestTemplate? 如何在RestTemplate(Spring Restful Client)中设置接受媒体类型 - How to set accept media type in RestTemplate (Spring restful client) 如何在Resttemplate Spring中做 - How to do in Resttemplate Spring 使用 SimpleClientHttpRequestFactory 时,如何使自定义 RestTemplate 使用标准 Spring Boots 的 Prometheus RestTemplate 指标进行检测? - How to make custom RestTemplate to instrument with standard Spring Boots' Prometheus RestTemplate metrics when using SimpleClientHttpRequestFactory? 如何在Spring中构建SOAP客户端? - How to build SOAP client in Spring? Spring Security SAML-如何配置客户端身份验证? - Spring Security SAML - how to configure client auth? 如何在 java spring 中配置 Feign 客户端 - How to i configure Feign Client in java spring 如何为 Spring 数据 Cassandra 配置 SSL 客户端 - How to configure SSL client for Spring Data Cassandra
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM