春の@Lookupアノテーション

1前書き

この簡単なチュートリアルでは、 @ Lookup アノテーションを通して、Springのメソッドレベルの依存性注入サポートを見ていきます。

2なぜ @ Lookup

@ Lookup のアノテーションが付けられたメソッドは、Springがそれを呼び出したときにそのメソッドの戻り型のインスタンスを返すように指示します

基本的に、Springはアノテーション付きメソッドをオーバーライドし、メソッドの戻り値の型とパラメータを BeanFactory#getBean. の引数として使用します。

@ Lookup は次の場合に役立ちます。

プロトタイプスコープのbeanをシングルトンbeanにインジェクトする

プロバイダ ) ** 手続き的に依存関係を注入する

@ Lookup は、XML要素 lookup-method とJavaで同等のものです。

3 @ Lookup を使う

3.1. プロトタイプスコープのBeanをシングルトンBeanに注入する

たまたまプロトタイプのSpring Beanを使用することにした場合、私たちのシングルトンのSpring BeanがこれらのプロトタイプのSpring Beanにどのようにアクセスするのかという問題にすぐに直面します。

@ Lookup はいくつかの点でより汎用的ですが、 Provider は確かに1つの方法です。

まず、後でシングルトンBeanに注入するプロトタイプBeanを作成しましょう。

@Component
@Scope("prototype")
public class SchoolNotification {
   //... prototype-scoped state
}

そして、 @ Lookup を使用するシングルトンBeanを作成したとします。

@Component
public class StudentServices {

   //... member variables, etc.

    @Lookup
    public SchoolNotification getNotification() {
        return null;
    }

   //... getters and setters
}

@ Lookup を使うと、シングルトンBeanを通じて SchoolNotification のインスタンスを取得できます。

@Test
public void whenLookupMethodCalled__thenNewInstanceReturned() {
   //... initialize context
    StudentServices first = this.context.getBean(StudentServices.class);
    StudentServices second = this.context.getBean(StudentServices.class);

    assertEquals(first, second);
    assertNotEquals(first.getNotification(), second.getNotification());
}

StudentServices では、スタブとして getNotification メソッドを残しました。

これは、Springが beanFactory.getBean(StudentNotification.class) の呼び出しでこのメソッドをオーバーライドするため、空のままにできるためです。

3.2. 依存関係を手続き的に注入する

さらに強力なのは、 @ Lookup を使用して手続き的に依存関係を注入できることです。

いくつかの状態で StudentNotification を強化しましょう。

@Component
@Scope("prototype")
public class SchoolNotification {
    @Autowired Grader grader;

    private String name;
    private Collection<Integer> marks;

    public SchoolNotification(String name) {
       //... set fields
    }

   //... getters and setters

    public String addMark(Integer mark) {
        this.marks.add(mark);
        return this.grader.grade(this.marks);
    }
}

さて、それは私たちが手続き的に提供することになる、いくつかのSpringのコンテキストとまた追加のコンテキストに依存しています。

それから、生徒データを取得してそれを保持するメソッドを StudentServices に追加できます。

public abstract class StudentServices {

    private Map<String, SchoolNotification> notes = new HashMap<>();

    @Lookup
    protected abstract SchoolNotification getNotification(String name);

    public String appendMark(String name, Integer mark) {
        SchoolNotification notification
          = notes.computeIfAbsent(name, exists -> getNotification(name)));
        return notification.addMark(mark);
    }
}

実行時に、Springはいくつかのトリックを追加して同じ方法でメソッドを実装します。

最初に、それは複雑なコンストラクタを呼び出すことができ、他のSpring Beanをインジェクトすることができるので、SchoolNotificationをSpringを意識したメソッドのように扱うことができます。

これを行うには、 beanFactory.getBean(SchoolNotification.class、name) を呼び出して getSchoolNotification を実装します。

次に、上の例のように、 __ @ Lookup - __アノテーション付きメソッドを抽象化することもできます。

abstract を使うのはスタブより少し見栄えがいいですが、それを使うことができるのは component-scan @ Bean -manage ** が周囲のbeanでない場合です。

@Test
public void whenAbstractGetterMethodInjects__thenNewInstanceReturned() {
   //... initialize context

    StudentServices services = context.getBean(StudentServices.class);
    assertEquals("PASS", services.appendMark("Alex", 89));
    assertEquals("FAIL", services.appendMark("Bethany", 78));
    assertEquals("PASS", services.appendMark("Claire", 96));
}

この設定で、Springの依存関係とメソッドの依存関係を SchoolNotification に追加できます。

4制限事項

@ Lookup の汎用性にもかかわらず、注目すべきいくつかの制限があります。

  • getNotificationのような @ Lookup アノテーション付きメソッド、 具体的でなければならない

__Studentのような周囲のクラスがコンポーネントスキャンされている場合。これは、コンポーネントスキャンが抽象Beanをスキップするためです。

  • __ @ Lookup - __アノテーション付きメソッドは、周囲の状況ではまったく機能しません。

クラスは @ Bean 管理対象です。

そのような状況で、プロトタイプBeanをシングルトンに注入する必要がある場合は、代わりに Provider を見ることができます。

5結論

このクイック記事では、Springの @ Lookup アノテーションを使用する方法とタイミング(プロトタイプスコープのBeanをシングルトンBeanに注入する方法、および依存関係を手続き的に注入する方法を含む)を学びました。

このチュートリアルで使われているすべてのコードはhttps://github.com/eugenp/tutorials/tree/master/spring-core[over Github]で見つけることができます。