2017-08-03 29 views
3

我正在尝试使用Spring Boot制作一个小型REST。 很久以前从未使用Spring和Java(Java 7)!如何与Spring进行异步休息?

在过去的2年中,我只使用Pyhton和C#(但就像我说的,我已经使用Java)。所以,现在,我正在尝试使用异步方法来创建REST,并检查了几个示例,但仍然不明白“正确的方法”来执行此操作。

查看以下文件:http://carlmartensen.com/completablefuture-deferredresult-async,爪哇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

@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; 
    }) 
    } 
} 

此代码给我预期的输出。 然后,看着另一个文件(很抱歉,我失去了联系),我看到春接受以下代码(给我的预期输出太):

@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/,在SpringBootApplication类中有@EnableAsync注释。 如果我包含@EnableAsync注释并创建asyncExecutor Bean,就像上一个链接的代码一样,我的应用程序不会在/test端点上返回任何内容(只有200 OK响应,但带有空白主体)。

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

谢谢!

+0

可以记录controller.test()和service.findByEmail()中的线程名称。我怀疑该操作不是异步 –

回答

3

因为@Async标注在UserRepository类findEmail方法中使用的响应主体是空白,这意味着没有数据返回给下面的句子User user = userRepository.findByEmail(email);因为findByEmail方法是在不同的线程上运行,并且将返回null,而不是一个List对象。

在声明@EnableAsync就是这个原因,当您使用@EnableAsync,因为它会激活findEmail的@Async方法在其他线程中运行它,为什么它只发生在@Async注释启用。

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

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

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

如果你想要得到预期的结果只是删除从findByEmail方法@Async注释,最后加@EnableAsync注释

如果您需要明确如何使用异步方法的想法,让我们说您必须调用三个方法,每个方法需要2秒才能完成,在正常情况下,您将调用方法1,方法2和方法3,在这种情况下,您的整个请求将耗时6秒。当您激活异步方法,那么你可以叫他们三个的,只是等待2秒钟,而不是6

这漫长的方法添加到用户的服务:

@Async 
public CompletableFuture<Boolean> veryLongMethod() { 

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

    return 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); 
    } 

最后测量把你的反应,如果它需要6秒以上,那么你没有运行异步方法,如果只需要2秒时间,那么你成功。

另请参阅以下文件:@Async AnnotationSpring async methodsCompletableFuture class

希望它能帮助。

+0

Tks。我在'Service'上的'findByEmail'方法中包含了一个睡眠(2s),并且调用了3次,只是为了测试,是的,需要6秒或更长时间。所以,我从'Repository'中删除了'@ Async',添加了@ @AsyncAsync',现在,所有东西都可以正常工作(需要超过2秒) –

1

我在触发异步方法时遇到性能问题。异步子线程开始执行很晚(大约20到30秒延迟)。我在我的主要SpringBoot应用程序类中使用ThreadPoolTask​​Executor()。如果您将性能视为一个因素,您也可以尝试相同的方法。