RestTemplate 设置每个请求的超时时间

pre*_*oid 8 spring resttemplate spring-boot

我有@Service几个方法,每个方法使用不同的 web api。每个调用都应该有一个自定义的读取超时。拥有一个 RestTemplate 实例并在每个方法中通过工厂更改超时是否是线程安全的

((HttpComponentsClientHttpRequestFactory)restTemplate.getRequestFactory())
.setReadTimeout(customMillis);
Run Code Online (Sandbox Code Playgroud)

我担心的是我正在更改工厂的超时时间,它不像RequestConfig. 考虑到这些方法可能同时被多个用户调用,这种方法是否是线程安全的?或者每个方法都应该有自己的RestTemplate

Tod*_*odd 7

选项 1:多个 RestTemplate

如果要更改创建的连接的属性,则RestTemplate每个配置都需要一个。我最近遇到了同样的问题,并且有两个版本RestTemplate,一个用于“短超时”,一个用于“长超时”。在每个组(短/长)中,我都能够分享RestTemplate.

让您的呼叫更改超时设置,创建连接,并希望最好的是等待发生的竞争条件。我会谨慎行事并创建多个RestTemplate.

例子:

@Configuration
public class RestTemplateConfigs {
    @Bean("shortTimeoutRestTemplate")
    public RestTemplate shortTimeoutRestTemplate() {
       // Create template with short timeout, see docs.
    }
    @Bean("longTimeoutRestTemplate")
    public RestTemplate longTimeoutRestTemplate() {
       // Create template with short timeout, see docs.
    }
}
Run Code Online (Sandbox Code Playgroud)

然后您可以根据需要将它们连接到您的服务中:

@Service
public class MyService {
    private final RestTemplate shortTimeout;
    private final RestTemplate longTimeout;

    @Autowired
    public MyService(@Qualifier("shortTimeoutRestTemplate") RestTemplate shortTimeout, 
                     @Qualifier("longTimeoutRestTemplate") RestTemplate longTimeout) {
        this.shortTimeout = shortTimeout;
        this.longTimeout = longTimeout;
    }

    // Your business methods here...
}
Run Code Online (Sandbox Code Playgroud)

选项 2:将调用封装在断路器中

如果您要调用外部服务,您可能应该为此使用断路器。Spring Boot 与 Hystrix 配合得很好,Hystrix 是断路器模式的一种流行实现。使用 hystrix,您可以控制您调用的每个服务的回退和超时。

假设您对服务 A 有两种选择:1) 便宜但有时慢 2) 贵但速度快。您可以使用 Hystrix 来放弃廉价/慢速,而在真正需要时使用昂贵/快速。或者你可以没有备份,只让 Hystrix 调用一个提供合理默认值的方法。

未经测试的示例:

@EnableCircuitBreaker
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp .class, args);
    }
}

@Service
public class MyService {
    private final RestTemplate restTemplate;

    public BookService(RestTemplate rest) {
        this.restTemplate = rest;
    }

    @HystrixCommand(
        fallbackMethod = "fooMethodFallback",
        commandProperties = { 
            @HystrixProperty(
                 name = "execution.isolation.thread.timeoutInMilliseconds", 
                 value="5000"
            )
        }
    )
    public String fooMethod() {
        // Your logic here.
        restTemplate.exchange(...); 
    }

    public String fooMethodFallback(Throwable t) {
        log.error("Fallback happened", t);
        return "Sensible Default Here!"
    }
}
Run Code Online (Sandbox Code Playgroud)

回退方法也有选项。您可以使用方法注释@HystrixCommand并尝试另一个服务调用。或者,您可以只提供一个合理的默认值。


pre*_*oid 6

初始化后从工厂更改超时RestTemplate只是等待发生的竞争条件(就像托德所解释的那样)。RestTemplate实际上是为了使用预先配置的超时而构建的,并且这些超时在初始化后保持不变。如果您使用Apache HttpClient,那么您可以设置RequestConfig每个请求,在我看来这是正确的设计。

我们已经RestTemplate在项目中的任何地方使用了,但目前我们无法承担随之而来的 http 客户端切换的重构。

现在我最终得到了一个RestTemplate池化解决方案,我创建了一个名为 RestTemplateManager 的类,并赋予它创建模板和池化它们的所有责任。该管理器有一个按服务和 readTimeout 分组的本地模板缓存。想象一下具有以下结构的缓存哈希图:

服务A|1000 -> RestTemplate

服务A|3000 -> RestTemplate

服务B|1000 -> RestTemplate

键中的数字是以毫秒为单位的 readTimeout(以后可以调整键以支持更多的 readTimeout)。因此,当ServiceA请求读取超时时间为1000ms的模板时,管理器将返回缓存的实例,如果不存在,则会创建并返回。

在这种方法中,我不用预先定义 RestTemplates,我只需要向上面的管理器请求 RestTemplate 即可。这也使初始化保持在最低限度。

直到我有时间放弃 RestTemplate 并使用更合适的解决方案为止。