1. 序章

このクイックチュートリアルでは、 @Lookup アノテーションを介して、Springのメソッドレベルの依存性注入のサポートを確認します。

2. なぜ@Lookupなのですか?

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

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

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

  • プロトタイプスコープのBeanをシングルトンBeanに注入する( Provider と同様)
  • 依存関係を手続き的に注入する

@Lookup は、JavaでXML要素lookup-methodに相当するものであることにも注意してください。

3. @Lookupを使用する

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

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

現在、 Provider は確かに一方向ですが、@Lookupはいくつかの点でより用途が広いです。

まず、後でシングルトン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 を使用すると、依存関係を手続き的に挿入できることです。これは、Providerでは実行できません。

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対応のメソッドのように扱うことができることに注意してください。

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

次に、上記の例のように、 @Lookup-注釈付きメソッドを抽象化できる場合があります。

abstract の使用は、スタブよりも少し見栄えがしますが、しないコンポーネントスキャンまたは@Bean-manageの場合にのみ使用できます。周囲の豆:

@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 の汎用性にもかかわらず、いくつかの注目すべき制限があります。

  • @Lookup getNotification、などの注釈付きメソッドは、 Student、などの周囲のクラスがコンポーネントスキャンされる場合は具体的である必要があります。 これは、コンポーネントスキャンが抽象Beanをスキップするためです。
  • @Lookup-周囲のクラスが@Beanで管理されている場合、アノテーション付きメソッドはまったく機能しません。

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

5. 結論

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

このチュートリアルで使用されるすべてのコードは、Githubにあります。