Java 如何使用Spring实现异步REST?

Java 如何使用Spring实现异步REST?,java,spring,rest,asynchronous,Java,Spring,Rest,Asynchronous,我想用弹簧靴休息一下。 我很久以前从未使用过Spring和Java(Java7) 在过去的两年中,我只使用了Python和C(但正如我所说,我已经使用了Java) 所以,现在,我尝试使用异步方法进行休息,并检查了几个示例,但我仍然不太清楚如何“正确地”进行休息 查看以下文档:,Java 8有CompletableFuture,我可以与Spring一起使用,因此,我编写了以下代码: 服务: @Service public class UserService { private UserRepo

我想用弹簧靴休息一下。 我很久以前从未使用过Spring和Java(Java7)

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

所以,现在,我尝试使用异步方法进行休息,并检查了几个示例,但我仍然不太清楚如何“正确地”进行休息

查看以下文档:,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);
  }
}
public interface UserRepository extends MongoRepository<User, String> {
  @Async
  findByEmail(String email);
}
@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;
    })
  }  
}
@服务
公共类用户服务{
私有用户存储库用户存储库;
//依赖注入
//这里不需要自动连线
// https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-spring-beans-and-dependency-injection.html
公共用户服务(用户存储库用户存储库){
this.userRepository=userRepository;
}
@异步的
公共CompletableFuture findByEmail(字符串电子邮件)引发InterrupedException{
User=userRepository.findByEmail(电子邮件);
返回CompletableFuture.completedFuture(用户);
}
}
存储库

@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
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;
    })
  }  
}
public interface UserRepository扩展了MongoRepository{
@异步的
findByEmail(字符串电子邮件);
}
RestController

@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
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;
    })
  }  
}
@RestController
公共类测试控制器{
私人用户服务;
公共测试控制器(用户服务用户服务){
this.userService=userService;
}
@请求映射(value=“test”)
public@ResponseBody CompletableFuture测试(@RequestParam(value=“email”,required=true)字符串电子邮件)引发InterruptedException{
返回userService.findByEmail(电子邮件)。然后返回applyasync(用户->{
返回用户;
})
}  
}
这段代码给出了预期的输出。 然后,查看另一个文档(抱歉,我丢失了链接),我看到Spring接受以下代码(这也给了我预期的输出):

@RequestMapping(value=“test”)
public@ResponseBody CompletableFuture测试(@RequestParam(value=“email”,required=true)字符串电子邮件)引发InterruptedException{
返回userService.findByEmail(电子邮件);
}  
}
这两种方法有区别吗

然后,看看下面的指南:,在
SpringBootApplication
类中有一个
@EnableAsync
注释。 如果我包括
@EnableAsync
注释,并像上一个链接中的代码一样创建一个
asynceducer
Bean,那么我的应用程序不会在
/test
端点上返回任何内容(只有一个200 OK响应,但主体为空)

那么,我的rest是异步的,没有
@enablesync
注释?
为什么当我使用
@EnableAsync
时,响应正文是空的?

响应正文是空的,因为
@Async
注释用于UserRepository类的findEmail方法,这意味着没有返回到以下句子的数据
User User=UserRepository.findByEmail(email)
当您声明
@enablesync
时,
@Async
注释被启用,这就是为什么只有当您使用
@enablesync
时才会发生注释的原因,因为它会激活findEmail的@Async方法在其他线程上运行它

方法
returnuserservice.findByEmail(email)
将返回一个从
UserService
类创建的
CompletableFuture
对象

与第二个方法调用不同的是,
theapplyasync
方法将从来自
userService.findByEmail(email)
的前一个方法创建一个全新的
CompletableFuture
,并且只返回来自第一个
CompletableFuture
的用户对象

 return userService.findByEmail(email).thenApplyAsync(user -> {
      return user;
    })
如果希望获得预期的结果,只需从findByEmail方法中删除
@Async
注释,最后添加
@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);
}
@Async
公共CompletableFuture veryLongMethod(){
试一试{
睡眠(2000L);
}捕捉(中断异常e){
e、 printStackTrace();
}
返回CompletableFuture.completedFuture(true);
}
从控制器中调用三次,如下所示

  @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);
  }  
@RequestMapping(value=“test”)
public@ResponseBody CompletableFuture测试(@RequestParam(value=“email”,required=true)字符串电子邮件)引发InterruptedException{
CompletableFuture boolean1=siteService.veryLongMethod();
CompletableFuture boolean2=siteService.veryLongMethod();
CompletableFuture boolean3=siteService.veryLongMethod();
CompletableFuture.allOf(boolean1,boolean2,boolean3).join();
返回userService.findByEmail(电子邮件);
}  
最后测量响应所需的时间,如果超过6秒,则表示您没有运行异步方法,如果仅需2秒,则表示您成功

另请参见以下文档:


希望能有所帮助。

触发异步方法时,我面临性能问题。异步子线程开始执行得很晚(大约延迟20到30秒)。我正在主SpringBoot应用程序类中使用ThreadPoolTaskExecutor()。如果你认为性能是一个因素,你也可以尝试同样的方法。

你可以在Control.Test.()和Service。FixByEnter()中记录线程名。我怀疑