如何使用Spring进行异步休息?

Rob*_*eia 16 java rest spring asynchronous

我正在尝试使用Spring Boot制作一个小型REST.从未使用过Spring并且很久以前使用过Java(Java 7)!

在过去的两年里,我只使用了Pyhton和C#(但就像我说的,我已经使用过Java).

所以,现在,我正在尝试使用异步方法创建REST,并检查了几个示例,但是,我仍然不太了解这样做的"正确方法".

查看以下文档:http://carlmartensen.com/completablefuture-deferredresult-async,Java 8具有CompletableFuture我可以与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);
  }
}
Run Code Online (Sandbox Code Playgroud)

存储库:

public interface UserRepository extends MongoRepository<User, String> {
  @Async
  findByEmail(String email);
}
Run Code Online (Sandbox Code Playgroud)

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;
    })
  }  
}
Run Code Online (Sandbox Code Playgroud)

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

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

这两种方法有区别吗?

然后,查看以下指南:https://spring.io/guides/gs/async-method/,类中有一个@EnableAsync注释SpringBootApplication.如果我包含@EnableAsync注释并asyncExecutor像上一个链接中的代码一样创建一个Bean,我的应用程序不会在/test端点上返回任何内容(只有200 OK响应,但是空白主体).

那么,我的休息是没有@EnableAsync注释的异步?为什么当我使用时@EnableAsync,响应体是空白的?

谢谢!

Dan*_* C. 12

响应主体是空白的,因为@Async注释在UserRepository类的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;
    })
Run Code Online (Sandbox Code Playgroud)

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

如果你需要澄清如何使用异步方法的想法,让我们说你必须调用三个方法,每个方法需要2秒才能完成,在正常情况下你会称之为method1,然后是method2,最后是method3,在这种情况下你整个请求将需要6秒.当您激活Async方法时,您可以调用其中的三个并等待2秒而不是6秒.

将这个长方法添加到用户服务:

@Async
public  CompletableFuture<Boolean> veryLongMethod()  {

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

    return CompletableFuture.completedFuture(true);
}
Run Code Online (Sandbox Code Playgroud)

并从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);
  }  
Run Code Online (Sandbox Code Playgroud)

最后测量您的响应时间,如果超过6秒,那么您没有运行异步方法,如果只需2秒,那么您就成功了.

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

希望它有所帮助.

  • Tks。我在“服务”的“ findByEmail”方法上添加了一个睡眠(2秒),并调用了3次,只是为了测试,是的,需要6秒钟或更长时间。因此,我从“存储库”中删除了“ @Async”,添加了“ @EnableAsync”,现在一切正常(耗时超过2秒) (2认同)