2017-08-03 7 views
3

私はSpring Bootを使用して小さなRESTを作ろうとしています。 Spring(Java 7)を使用したことがありません。Springで非同期の残りの部分を作る方法は?

私はPythtonとC#だけを使っています(しかし、私が言ったように、すでにJavaを使いました)。

これで、非同期メソッドを使用してRESTを作成しようとしていますが、いくつかの例をチェックしましたが、これを行うための正しい方法がわかりません。

次のドキュメントを見て:

サービス

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

リポジトリhttp://carlmartensen.com/completablefuture-deferredresult-async、Javaの8は、私は春で使用できるCompletableFutureを持っているので、私は次のコードを作りました:

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

は2つの方法の違いはありますか?

次に、以下のガイドを参照してください:https://spring.io/guides/gs/async-method/SpringBootApplicationクラスに注釈があります。 注釈を含めて、最後のリンクのコードのようにasyncExecutor Beanを作成すると、/testエンドポイントでは何も返されません(200 OK応答のみですが、空白の本体があります)。

したがって、残りの部分は@EnableAsyncアノテーションなしで非同期ですか? @EnableAsyncを使用すると、応答本文は空白になりますか?

ありがとうございます! @AsyncアノテーションがUserRepositoryクラスのfindEmailの方法で使用するため

+0

controller.test()とservice.findByEmail()にスレッド名を記録することができます。私は操作が非同期ではないと思う。 –

答えて

3

応答本体が空白である、それはデータがfindByEmail方法は、他の別のスレッドで実行されているため、次の文User user = userRepository.findByEmail(email);に戻されず、nullを返す代わりになりますがあることを意味しますListオブジェクトあなたは@EnableAsyncを使用する場合、それは他のスレッドでそれを実行するためにfindEmail方法の@Asyncを活性化させるので、それが唯一の起こる理由です@EnableAsyncを宣言するとき

@Async注釈が有効になっています。

return userService.findByEmail(email);メソッドは、UserServiceクラスから作成されたCompletableFutureオブジェクトを返します。

二メソッド呼び出しとの違いは、thenApplyAsync方法がuserService.findByEmail(email)から来て、以前のものから全く新しいCompletableFutureを作成し、最初のCompletableFutureから来ているユーザーオブジェクトを返すことです。

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

あなたが期待される結果を取得したい場合は、単にfindByEmailメソッドから@Async注釈を削除し、最終的にはあなたが非同期メソッドを使用する方法のアイデアを明確にする必要がある場合は、それを言うことができます@EnableAsync注釈に

を追加3つのメソッドを呼び出す必要があり、それぞれが2秒かかります。通常のシナリオでは、method1、method2、最後にmethod3と呼びます。その場合、要求全体に6秒かかります。あなたが非同期的なアプローチを有効にすると、あなたはそれらの3を呼び出すことができますし、単にユーザーサービスにこの長いメソッドを追加します。代わりに6

の2秒待つ:コントローラから3回

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

は、最後にそれがわずか2秒かかるならば、あなたは成功し、それが6秒以上かかる場合、あなたは非同期メソッドを実行していない、あなたの応答にかかる時間を測定します。

はまた、次のドキュメントを参照してください:@Async AnnotationSpring async methodsCompletableFuture class

はそれが役立つ願っています。

+0

Tks。私は 'Service'の' findByEmail'メソッドにsleep(2s)を入れ、テストのために3回呼び出しました。そして、はい、6秒以上かかります。そこで、私は '@ Async'を' Repository'から削除し、 '@ EnableAsync'を追加しました。そして今、すべてがうまく動作します(2秒より少し時間がかかります) –

1

非同期メソッドをトリガするときにパフォーマンス上の問題に直面しています。非同期の子スレッドは非常に遅く実行を開始します(約20〜30秒の遅延)。私は主なSpringBootアプリケーションクラスでThreadPoolTask​​Executor()を使用しています。また、パフォーマンスとして考える場合は、同じことを試すことができます。

関連する問題