Lombokによる春のコンストラクタインジェクション

1前書き

Lombokは定型コードを克服するための非常に便利なライブラリです。まだ慣れていないのであれば、前回のチュートリアル - はじめに を見てみることを強くお勧めします。

この記事では、Springの「コンストラクタベースの依存性注入」と組み合わせたときの使いやすさについて説明します。

2コンストラクタベースの依存性注入

c __onstructorベースのDependency Injection __を使ってSpringで依存関係を結び付ける良い方法。この方法では、コンポーネントの依存関係を明示的にコンストラクタに渡す必要があります。

フィールドベースの依存性注入 とは対照的に、これには多くの利点もあります。

  • テスト固有の設定コンポーネントを作成する必要はありません -

依存関係はコンストラクタに明示的に注入されます ** 一貫した設計 - 必要なすべての依存関係が強調されている

コンストラクターの定義によって保護されている ** シンプルな単体テスト - Spring Frameworkのオーバーヘッドを削減

  • final キーワードを使用する自由を取り戻しました

しかしながら、コンストラクタを書く必要性のために、それはかなり大きいコードベースをもたらすために使用します。 GreetingService と__FarewellServiceの2つの例を考えます。

@Component
public class GreetingService {

    @Autowired
    private Translator translator;

    public String produce() {
        return translator.translate("hello");
    }
}
@Component
public class FarewellService {

    private final Translator translator;

    public FarewellService(Translator translator) {
        this.translator = translator;
    }

    public String produce() {
        return translator.translate("bye");
    }
}

基本的に、両方のコンポーネントは同じことをします - タスク固有の単語で設定可能な Translator を呼び出します。

ただし、2番目のバリエーションは、コンストラクタの定型句がコードにまったく価値をもたらさないため、はるかに難読化されています。

  • 最新のSpringリリースでは、コンストラクタに @ Autowired アノテーションを付ける必要はありません。**

3 Lombokによるコンストラクター注入

Lombok を使用すると、すべてのクラスのフィールド( @ AllArgsConstructor を含む)またはすべての final クラスのフィールド( @ RequiredArgsConstructor を含む)のいずれかに対してコンストラクターを生成できます。さらに、まだ空のコンストラクタが必要な場合は、追加の @ NoArgsConstructor アノテーションを追加できます。

前の2つに似た3番目のコンポーネントを作成しましょう。

@Component
@RequiredArgsConstructor
public class ThankingService {

    private final Translator translator;

    public String produce() {
        return translator.translate("thank you");
    }
}

上記のアノテーションは Lombok にコンストラクタを生成させます。

@Component
public class ThankingService {

    private final Translator translator;

    public String thank() {
        return translator.translate("thank you");
    }

   /**  Generated by Lombok ** /    public ThankingService(Translator translator) {
        this.translator = translator;
    }
}

4. 複数のコンストラクタ

コンポーネント内にコンストラクタが1つしかない限り、コンストラクタに注釈を付ける必要はなく、Springは新しいオブジェクトをインスタンス化するための正しいコンストラクタとして明確にそれを選択できます。それ以上ある場合は、IoCコンテナで使用されるものに注釈を付ける必要もあります。

ApologizeService の例を考えます。

@Component
@RequiredArgsConstructor
public class ApologizeService {

    private final Translator translator;
    private final String message;

    @Autowired
    public ApologizeService(Translator translator) {
        this(translator, "sorry");
    }

    public String produce() {
        return translator.translate(message);
    }
}

上記のコンポーネントは、コンポーネントが作成された後に変更することができない message フィールドで任意に設定可能です(したがって setter の欠如)。そのため、2つのコンストラクタを提供する必要がありました。1つは完全な設定を持つもので、もう1つは暗黙のデフォルト値の message を持つものです。

いずれかのコンストラクタに @ Autowired @ Inject 、または @ Resource のアノテーションが付いていない限り、Springはエラーをスローします。

Failed to instantiate[...]: No default constructor found;

__Lombok - が生成したコンストラクタに注釈を付けたい場合は、 @ AllArgsConstructor onConstructor__パラメータを使用して注釈を渡す必要があります。

@Component
@RequiredArgsConstructor(onConstructor = @____(@Autowired))
public class ApologizeService {
   //...
}

onConstructor パラメーターは、生成されたコンストラクターに配置される注釈の配列(またはこの特定の例のように単一の注釈)を受け入れます。下位互換性の問題のため、二重下線の慣用句が導入されました。ドキュメントによると:

妙な構文の理由は、この機能をjavac 7コンパイラで機能させるためです。 @ _`型は、実際には存在しない注釈型 `(二重下線)への注釈参照です。アノテーションプロセッサが後で ` _`型を作成する可能性があるので、これはエラーのためにjavac 7がコンパイルプロセスを中止するのを遅らせます。

=== 5概要

このチュートリアルでは、定型コードの増加という点で、コンストラクタベースのDIよりもフィールドベースのDIを優先する必要がないことを示しました。

Lombokのおかげで、ランタイムにパフォーマンスに影響を与えることなく共通コード生成を自動化することができます。長い、あいまいなコードを単一行の注釈の使用に省略します。

チュートリアル中に使用されたコードはhttps://github.com/eugenp/tutorials/tree/master/spring-core[GitHubで利用可能]です。