web-dev-qa-db-ja.com

RestTemplateは静的にグローバルに宣言する必要がありますか?

私はコードでJava Callable Futureを使用しています。以下はfutureとcallablesを使用する私のメインコードです-

public class TimeoutThread {

    public static void main(String[] args) throws Exception {

        ExecutorService executor = Executors.newFixedThreadPool(5);
        Future<String> future = executor.submit(new Task());

        try {
            System.out.println("Started..");
            System.out.println(future.get(3, TimeUnit.SECONDS));
            System.out.println("Finished!");
        } catch (TimeoutException e) {
            System.out.println("Terminated!");
        }

        executor.shutdownNow();
    }
}

以下は、Callableインターフェイスを実装するTaskクラスです。ホスト名に応じてURLを生成し、RestTemplateを使用してSERVERSを呼び出す必要があります。最初のホスト名に例外がある場合は、別のホスト名のURLを生成して、電話をかけてみます。

class Task implements Callable<String> {
    private static RestTemplate restTemplate = new RestTemplate();

    @Override
    public String call() throws Exception {

    //.. some code

    for(String hostname : hostnames)  {
            if(hostname == null) {
                continue;
            }
            try {
                String url = generateURL(hostname);         
                response = restTemplate.getForObject(url, String.class);

                // make a response and then break
                break;

            } catch (Exception ex) {
                ex.printStackTrace(); // use logger
            }
        }
    }
}

だから私の質問はRestTemplateを静的グローバル変数として宣言する必要がありますか?または、このシナリオでは静的であってはなりませんか?

18
AKIWEB

staticまたはインスタンスのどちらでも構いません。

HTTPリクエストを作成するためのRestTemplateのメソッドはスレッドセーフであるため、RestTemplateインスタンスごとにTaskインスタンスがあるか、すべてのTaskインスタンスの共有インスタンスがあるかは関係ありません(ガベージコレクションを除く)。

個人的には、RestTemplateクラスの外にTaskを作成し、それを引数としてTaskコンストラクターに渡します。 (可能な場合は常に制御の反転を使用してください。)

15

並行性の観点からは、それは問題ではありません。 RestTemplateはスレッドセーフであるため、単一のインスタンスまたは複数のインスタンスは、プログラムの適切な機能とは無関係です。

ただし、示されているように、代わりにAsyncRestTemplateを検討することをお勧めします ここ

また、他の人が言及しているように、RESTクライアントの作成とその使用を分離するためのIoCアプローチを検討する必要があります。 This MartinFowlerによる記事はトピック。

3
Vidya

私の特定のケースでは、RestTemplateのインスタンスを複数持つ必要がある理由がいくつか見つかりました。

RestTemplateはリモートエンドポイントを呼び出す方法ですが、HTTP統合は一見シンプルに見えます。すべてのAPI呼び出しに適用されない特別なシナリオを見つけ始めたときは、ケースバイケースでいくつかの設定を定義する方法が必要であることに気付いたときです。基礎。

このようなシナリオの例は次のとおりです。

  • 社内にはさまざまなチームがあり、モデルで使用したい時間形式に誤って同意しませんでした。現在、さまざまなチームのさまざまなAPIがさまざまな時間形式を使用しているため、これらのケースに対してさまざまなJSONマッパー設定を定義する必要がありました。これは、サードパーティのサービスを呼び出す必要がある場合にも発生する可能性があります。
  • 私たちが呼び出すすべてのAPIが同じサービスレベル契約を結んでいるわけではなく、年間を通じて同じように動作するわけでもありません。ハイシーズンには、一部のAPIがより多くのトラフィックなどをサポートする必要がある場合があります。これは、接続タイムアウト設定がAPIごとに異なり、場合によっては要件によっても異なる可能性があることを意味します。そのため、接続タイムアウト、読み取りタイムアウト、書き込みタイムアウトなどの設定は、呼び出すサービスによって異なる構成になる場合があります。
  • おそらく、Hytrixのようなサーキットブレーカー設定をサービスごとに構成する必要がある場合があるため、サービスごとにRestTemplateインスタンスを設定すると、ケースバイケースで設定を構成する機能が向上します。
2
Edwin Dalorzo

すでに述べたように、RestTemplateはスレッドセーフです。

ただし、単体テストの場合、静的変数を使用すると、彼の呼び出しをモックするためのいくつかの問題が発生します。したがって、クラスコンストラクターを使用してRestTemplateを挿入することを検討してください。

@Service
class LoginService {

    private final RestTemplate restTemplate;

    public LoginService(final RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }
}
1
Dherik