春の@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]で見つけることができます。