春天顶部

通过参考,使用Spring 5和Spring Boot 2开始学习春天课程:

>>学习春天
休息顶部

通过参考,使用Spring 5和Spring Boot 2开始学习春天课程:

>>查看课程

1.概述

在本教程中,我们将探讨一些可能的方法来实现Spring REST API的请求超时。

我们将讨论每个人的好处和缺点。请求超时对于防止用户体验差,特别是如果我们可以默认到资源太长时,我们可以默认。这种设计模式称为断路器模式,但我们不会详细说明这里。

2。@Transactional.超时

我们可以在数据库调用上实现请求超时的方式是利用Spring的@Transactional.注解。它有一个超时我们可以设置的财产。此属性的默认值为-1,其等同于根本没有任何超时。对于超时值的外部配置,不同的属性 -超时- 必须使用。

例如,假设我们将此超时设置为30.如果注释方法的执行时间超过此秒数,则将抛出异常。这对滚动长期运行的数据库查询可能很有用。

要在操作中查看此操作,让我们编写一个非常简单的JPA存储库层,它将表示一个需要太长的外部服务,无法完成并导致超时发生。此JparePository扩展程序中的时间昂贵方法:

公共接口BookRepository扩展了Jparepository  {default int wastetime(){int i = integer.min_value;而(i 

如果我们调用我们的浪费时间()方法虽然在一个超时1秒的事务内,在方法完成执行之前将经过超时:

@getmapping(“/作者/事务性”)@transactional(timeout = 1)公共字符串getWithTransactionTimeout(@RequestParam字符串标题){bookrepository.wastetime();返回bookrepository.findbyid(标题).map(书:: getauthor).orelse(“没有为此标题找到书籍。”);}

调用此端点导致500个HTTP错误,我们可以转换为更有意义的响应。它还需要很少的设置来实现。

但是,此超时解决方案存在一些缺点。

首先,它取决于具有具有弹簧管理交易的数据库。它也没有全球适用于项目,因为必须在需要它的每种方法或类上存在注释。它也不允许次级第二精度。最后,当达到超时时,它不会切割请求,因此请求实体仍然必须等待全部时间。

让我们考虑一些其他选择。

3. Resilience4J.时分米

Resilience4J是一个图书馆主要致力于管理远程通信的容错。它的时分米模块是我们在这里感兴趣的。

首先,我们必须包括Resilience4j-timelimiter.依赖性在我们的项目中:

<依赖项>  io.github.resilience4j   RESLIENCES4J-TIMELIMITER   1.6.1  

接下来,让我们定义一个简单的时分米超时持续时间为500毫秒:

私有时间iterimelimiter yourmelimiter = timelimiter.cof(timelimiterConfig.custom().TimeOutduration(duration.ofmillis(500))。build());

这可以很容易地配置。

我们可以使用我们的时分米包裹我们的相同逻辑@Transactional.使用的示例:

@getmapping(“/ author / resilience4j”)public callable  getwithresilience4jtimelimiter(@requestparam字符串标题){return timelimiter.decoratefuturesupplier(outtimelimiter,() - > performablefuture.supplyasync(() - > {bookrepository.wastetime();返回bookrepository.findbyid(title).map(书:: getauthor).orelse(“未找到此名称的书籍”。);});}

时分米提供了几个好处@Transactional.解决方案。即,它支持超秒的精度和立即通知超时响应。但是,它仍然必须在需要超时的所有端点中手动包含,需要一些冗长的包装代码,并且它产生的错误仍然是通用500 HTTP错误。此外,它需要返回一个可调用而不是一个原始细绳。

时分米仅包括一个子集Resilience4J的功能并且与断路器图案很好地接口。

4. Spring MVC请求超时

春天为我们提供了一个叫做的财产spring.mvc.async.request-timeout.。此属性允许我们以毫秒精度定义请求超时。

让我们使用750毫秒超时定义属性:

spring.mvc.async.request-timeout = 750

此属性是全局和外部可配置的,但类似于时分米解决方案,它只适用于返回a的端点可谴责。让我们定义类似于的端点时分米示例,但不需要将逻辑包装在一起期货或提供A.时分米

@getmapping(“/ author / mvc-request-timeout”)public callable  getwithmvcrequesttimeout(@requestparam字符串标题){return() - > {bookrepository.wastetime();返回bookrepository.findbyid(标题).map(书:: getauthor).orelse(“没有为此标题找到书籍。”);};}

我们可以看到代码不太详细,并且当我们定义应用程序属性时,Spring自动实现配置。一旦达到超时,就立即返回响应,并且甚至返回更具描述性的503 HTTP错误而不是通用500。此外,我们项目中的每个端点都会自动继承此超时配置。

让我们考虑另一个选项,允许我们定义超时的粒度。

5。WebClient.超时

而不是为整个端点设置超时,而不是设置超时,也许我们希望只需一个外部呼叫的超时。WebClient.是春天的反应网络客户端并允许我们配置响应超时。

也可以配置超时春年长resttemplate.目的。但是,大多数开发人员现在更喜欢WebClient.超过resttemplate.

要使用WebClient,我们必须先添加Spring的WebFlux依赖到我们的项目:

<依赖项>  org.springframework.boot   Spring-Boot-Starter-WebFlux   2.4.2  

让我们定义一个WebClient.使用250毫秒的响应超时,我们可以使用它在其基本URL中通过LocalHost调用自己:

@bean public webclient webclient(){return webclient.builder().baseurl(“http:// localhost:8080”).clientConnector(new acctorclienthttpConnector(httpclient.create()。resportEtimeout(duration.ofmillis(250)))))。建造();}

显然,我们可以轻松地在外部配置此超时值。我们还可以在外部配置基本URL,以及其他几个可选属性。

现在我们可以注明我们的WebClient.进入我们的控制器并用它来称呼我们自己/交易端点,仍有1秒的超时。自我们配置了我们的WebClient.在250毫秒的超时时,我们应该看到它的失败比1秒更快。

这是我们的新终点:

@getmapping(“/ author / webclient”)public string getwithwithwebclient(@requestparam字符串标题){return webclient.get()。uri(uribuilder  - > ulibuilder .path(“/ author / transactional”).queryparam(“标题”,标题).build()).retrieve().bodytomono(string.class).block();}

在调用这个端点之后,我们看到我们确实收到了WebClient.“超时以500个HTTP错误响应的形式。我们还可以查看日志以查看下游@Transactional.超时。但当然,如果我们称为外部服务而不是localhost,它会将其超时打印。

配置不同后端服务的不同请求超时可能是必要的,并且可以使用此解决方案进行。此外,单核细胞增多症或者助势回复发布商返回WebClient.包含很多误差处理方法处理通用超时错误响应。

六,结论

我们刚刚探索了几种不同的解决方案来实现本文中的请求超时。在决定使用哪一个时,有几个因素需要考虑。

如果我们想在数据库请求上放置超时,我们可能想要使用Spring的@Transactional.方法及其超时财产。如果我们试图与更广泛的断路器模式集成,使用弹性4J时分米会有意义。使用Spring MVC请求超时属性最适合为所有请求设置全局超时,但我们可以轻松地定义每个资源的更加粒度超时WebClient.

对于所有这些解决方案的工作示例,代码已准备就绪并从框中运行在github上

弹簧底部

使用Spring 5和Spring Boot 2开始,通过学习春天课程:

>>课程
休息底部

使用Spring 5和Spring Boot 2开始,通过学习春天课程 :

>>查看课程
评论在本文上关闭!