2017-08-03 64 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()。如果您將性能視爲一個因素,您也可以嘗試相同的方法。