当前位置: 首页 > 面试题库 >

如何使用Spring制作异步REST?

江光明
2023-03-14
问题内容

我正在尝试使用Spring Boot创建一个小的REST。我很久以前从未使用过Spring,也没有使用过Java(Java 7)!

在过去的两年中,我只使用了Python和C#(但正如我所说,我已经使用过Java)。

因此,现在,我正在尝试使用异步方法制作REST,并检查了几个示例,但是,我仍然不太了解执行此操作的“正确方法”。

查看以下文档: http
//carlmartensen.com/completablefuture-deferredresult-
async
CompletableFuture我可以将Java 8 与Spring一起使用,因此,我编写了以下代码:

服务内容

@Service
public class UserService {
  private UserRepository userRepository;

  // dependency injection
  // don't need Autowire here
  // https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-spring-beans-and-dependency-injection.html
  public UserService(UserRepository userRepository) {
    this.userRepository = userRepository;
  }

  @Async
  public CompletableFuture<User> findByEmail(String email) throws InterrupedException {
    User user = userRepository.findByEmail(email);
    return CompletableFuture.completedFuture(user);
  }
}

仓库

public interface UserRepository extends MongoRepository<User, String> {
  @Async
  findByEmail(String email);
}

RestController

@RestController
public class TestController {

  private UserService userService;

  public TestController(UserService userService) {
    this.userService = userService;
  }

  @RequestMapping(value = "test")
  public @ResponseBody CompletableFuture<User> test(@RequestParam(value = "email", required = true) String email) throws InterruptedException {
    return userService.findByEmail(email).thenApplyAsync(user -> {
      return user;
    })
  }  
}

这段代码给了我预期的输出。然后,查看另一个文档(对不起,我丢失了链接),我看到Spring接受以下代码(这也给了我预期的输出):

  @RequestMapping(value = "test")
  public @ResponseBody CompletableFuture<User> test(@RequestParam(value = "email", required = true) String email) throws InterruptedException {
    return userService.findByEmail(email);
  }  
}

两种方法之间有区别吗?

然后,查看以下指南:https :
//spring.io/guides/gs/async-method/,@EnableAsyncSpringBootApplication类中有一个注释。如果我包括@EnableAsync注解并asyncExecutor像上一个链接中的代码一样创建一个Bean,则我的应用程序/test端点上什么也不返回(仅返回200
OK,但正文为空)。

所以,我的其余部分没有@EnableAsync注释就异步了吗?为什么在使用时@EnableAsync,响应正文为空白?


问题答案:

响应正文为空,因为在@AsyncUserRepository类的findEmail方法中使用了注释,这意味着没有数据返回到下面的句子,User user = userRepository.findByEmail(email);因为findByEmail方法正在其他线程上运行,并且将返回null而不是List对象。

@Async当您声明该注释@EnableAsync仅在使用时才发生时@EnableAsync,便启用了该注释,因为它激活了findEmail方法的@Async以便在其他线程上运行它。

该方法return userService.findByEmail(email);将返回CompletableFutureUserService类创建的对象。

与第二个方法调用的不同之处在于,该thenApplyAsync方法将创建一个CompletableFuture与前一个方法完全不同的新方法,userService.findByEmail(email)并且仅返回第一个方法的用户对象CompletableFuture

 return userService.findByEmail(email).thenApplyAsync(user -> {
      return user;
    })

如果要获得预期的结果,只需@Async从findByEmail方法中删除注释,最后添加@EnableAsync注释

如果您需要澄清如何使用异步方法的想法,可以说您必须调用三个方法,每个方法需要2秒钟才能完成,在正常情况下,您将其称为method1,然后称为method2,最后称为method3。整个请求将花费6秒。激活异步方法后,您可以调用其中三个,而只需等待2秒钟而不是6秒钟。

将此长方法添加到用户服务中:

@Async
public  CompletableFuture<Boolean> veryLongMethod()  {

    try {
        Thread.sleep(2000L);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    return CompletableFuture.completedFuture(true);
}

然后从Controller调用它三遍

  @RequestMapping(value = "test")
  public @ResponseBody CompletableFuture<User> test(@RequestParam(value = "email", required = true) String email) throws InterruptedException {
        CompletableFuture<Boolean> boolean1= siteService.veryLongMethod();
        CompletableFuture<Boolean> boolean2= siteService.veryLongMethod();
        CompletableFuture<Boolean> boolean3= siteService.veryLongMethod();

        CompletableFuture.allOf(boolean1,boolean2,boolean3).join();
    return userService.findByEmail(email);
  }

最后测量响应所花费的时间,如果花费了6秒钟以上,则说明您未运行Async方法,如果花费了2秒钟,则说明您成功了。

另请参阅以下文档:@Async
Annotation
,Spring异步方法,CompletableFuture类

希望对您有所帮助。



 类似资料:
  • 我的应用程序是简单的3-层Spring Boot rest Web服务,具有通常的同步endpoint。但是由于从我的服务发送请求的下游系统获得响应的时间相当长(有点像60秒),我需要向我的服务添加对异步REST调用的支持,以保存上游系统免于等待响应。换句话说,如果对下游系统的响应需要超过60秒(超时),那么上游系统会断开与我的服务的连接并继续运行... 但是当响应到来时,我的服务使用来自上游系统

  • 我需要在函数中运行各种步骤,但步骤必须按特定顺序运行。我尝试实现一个函数,如下所示: 控制台中的预期结果应该是1,2,3,但我得到了3,2,1。似乎忽略了参数。 编辑功能在上面的示例中仅用于模拟繁重的任务。在我的项目中,我不会使用它。事实上,我需要连接到一个数据库,然后在进入下一步之前重新格式化结果。即使包括,2也会在1之前登录。换句话说,空列表被传递到我的图形,因为没有考虑。以下是我当前的代码:

  • 我正在为一家德国公司评估Dart,将各种Java程序移植到Dart,并对结果进行比较和分析。在浏览器中,飞镖轻松获胜。对于服务器来说,软件性能似乎是一个严重的问题(请看我的这个问题),但这基本上得到了缓解。 现在我正在移植一些“简单”的命令行工具,我没想到会有任何严重的问题,但至少有一个问题。一些工具确实会发出HTTP请求来收集一些数据,独立的Dart虚拟机只以异步方式支持它们。纵观所有我能找到的

  • 我遵循了spring批处理文档,无法异步运行我的作业。 因此,我从一个web容器运行该作业,该作业将通过RESTendpoint触发。 我想让JobInstance ID在完成整个作业之前传递它作为响应。因此,他们可以稍后使用JobInstance ID检查作业的状态,而不是等待。但我没能让它工作。下面是我尝试过的示例代码。请让我知道我错过了什么或错了什么。 BatchConfig创建异步JobL

  • 在Facebook关于Flux架构的演讲中,Jing在12:17提到dispatcher强制要求,在当前操作被商店完全处理之前,不能调度任何操作。 这里的调度员是执行没有级联效应的主要部分;一旦一个操作进入商店,在商店完全处理完它之前,您不能再放入另一个操作。 那么,我的问题是,如何正确地处理可能从存储区中删除的长时间运行的异步操作(例如,Ajax请求,或处理其他外部异步API)--任何阻止完成操

  • 问题内容: 如何从异步函数返回值?我试图喜欢这个 它给了我, 问题答案: 您不能超出范围。为了获得预期的结果,您应该将其包装到异步IIFE中,即 样品。 有关更多信息 由于返回一个Promise,因此可以将其省略,如下所示: 然后像以前一样做