我正在尝试使用Spring Boot创建一个小的REST。我很久以前从未使用过Spring,也没有使用过Java(Java 7)!
在过去的两年中,我只使用了Python和C#(但正如我所说,我已经使用过Java)。
因此,现在,我正在尝试使用异步方法制作REST,并检查了几个示例,但是,我仍然不太了解执行此操作的“正确方法”。
CompletableFuture
服务内容 :
@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/,@EnableAsync在SpringBootApplication类中有一个注释。如果我包括@EnableAsync注解并asyncExecutor像上一个链接中的代码一样创建一个Bean,则我的应用程序在/test端点上什么也不返回(仅返回200 OK,但正文为空)。
@EnableAsync
SpringBootApplication
asyncExecutor
/test
所以,我的其余部分没有@EnableAsync注释就异步了吗?为什么在使用时@EnableAsync,响应正文为空白?
响应正文为空,因为在@AsyncUserRepository类的findEmail方法中使用了注释,这意味着没有数据返回到下面的句子,User user = userRepository.findByEmail(email);因为findByEmail方法正在其他线程上运行,并且将返回null而不是List对象。
@Async
User user = userRepository.findByEmail(email);
@Async当您声明该注释@EnableAsync仅在使用时才发生时@EnableAsync,便启用了该注释,因为它激活了findEmail方法的@Async以便在其他线程上运行它。
该方法return userService.findByEmail(email);将返回CompletableFuture从UserService类创建的对象。
return userService.findByEmail(email);
UserService
与第二个方法调用的不同之处在于,该thenApplyAsync方法将创建一个CompletableFuture与前一个方法完全不同的新方法,userService.findByEmail(email)并且仅返回第一个方法的用户对象CompletableFuture。
thenApplyAsync
userService.findByEmail(email)
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类
希望对您有所帮助。