修飾子を使用したアノテーションベースのオートワイヤーの微調整
@Primary
および @Fallback
は、1 つのプライマリ (または非フォールバック) 候補を決定できる場合に、複数のインスタンスで型別のオートワイヤーを使用する効果的な方法です。
選択プロセスをより詳細に制御する必要がある場合は、Spring の @Qualifier
アノテーションを使用できます。修飾子の値を特定の引数に関連付けて、型一致のセットを絞り込み、引数ごとに特定の Bean が選択されるようにすることができます。最も単純なケースでは、次の例に示すように、これは単純な説明値になります。
Java
Kotlin
public class MovieRecommender {
@Autowired
@Qualifier("main")
private MovieCatalog movieCatalog;
// ...
}
class MovieRecommender {
@Autowired
@Qualifier("main")
private lateinit var movieCatalog: MovieCatalog
// ...
}
次の例に示すように、個々のコンストラクター引数またはメソッドパラメーターに @Qualifier
アノテーションを指定することもできます。
Java
Kotlin
public class MovieRecommender {
private final MovieCatalog movieCatalog;
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(@Qualifier("main") MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
class MovieRecommender {
private lateinit var movieCatalog: MovieCatalog
private lateinit var customerPreferenceDao: CustomerPreferenceDao
@Autowired
fun prepare(@Qualifier("main") movieCatalog: MovieCatalog,
customerPreferenceDao: CustomerPreferenceDao) {
this.movieCatalog = movieCatalog
this.customerPreferenceDao = customerPreferenceDao
}
// ...
}
次の例は、対応する Bean 定義を示しています。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier value="main"/> (1)
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier value="action"/> (2)
<!-- inject any dependencies required by this bean -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
1 | main 修飾子値を持つ Bean は、同じ値で修飾されたコンストラクター引数に関連付けられます。 |
2 | action 修飾子値を持つ Bean は、同じ値で修飾されたコンストラクター引数に関連付けられます。 |
フォールバック一致の場合、Bean 名はデフォルトの修飾子値と見なされます。ネストされた修飾子要素の代わりに main
の id
を使用して Bean を定義すると、同じ一致結果が得られます。ただし、この規則を使用して特定の Bean を名前で参照することはできますが、@Autowired
は基本的に、オプションのセマンティック修飾子を使用した型駆動型注入に関するものです。これは、Bean 名のフォールバックがある場合でも、修飾子の値は、型一致のセット内で常に狭義のセマンティクスを持つことを意味します。それらは、一意の Bean id
への参照を意味的に表現しません。適切な修飾子の値は main
または EMEA
または persistent
で、Bean id
から独立した特定のコンポーネントの特性を表します。これは、前述の例のような匿名 Bean 定義の場合に自動生成される場合があります。
前述のように、修飾子は型付きコレクションにも適用されます。たとえば、Set<MovieCatalog>
に適用されます。この場合、宣言された修飾子に従って、一致するすべての Bean がコレクションとして注入されます。これは、修飾子が一意である必要がないことを意味します。むしろ、それらはフィルタリング条件を構成します。例: 同じ修飾子値「アクション」を持つ複数の MovieCatalog
Bean を定義できます。これらはすべて、@Qualifier("action")
アノテーションが付けられた Set<MovieCatalog>
に注入されます。
型が一致する候補内で、修飾子の値がターゲット Bean 名に対して選択されるようにすると、インジェクションポイントで バージョン 6.1 以降、これには |
名前による注入の代替として、JSR-250 @Resource
アノテーションを検討してください。これは、特定のターゲットコンポーネントを一意の名前で識別するように意味的に定義されており、宣言された型はマッチングプロセスには関係ありません。@Autowired
は、かなり異なる意味を持ちます。型によって候補 Bean を選択した後、指定された String
修飾子の値は、型選択された候補内でのみ考慮されます (たとえば、同じ修飾子ラベルでマークされた Bean に対して account
修飾子をマッチングします)。
コレクション、Map
、または配列型として定義されている Bean の場合、@Resource
は、特定のコレクションまたは配列 Bean を一意の名前で参照する適切なソリューションです。ただし、要素の型情報が @Bean
戻り値の型シグネチャーまたはコレクション継承階層に保存されている限り、コレクション、Map
、配列型を Spring の @Autowired
型マッチングアルゴリズムでマッチングすることもできます。この場合、前の段落で説明したように、修飾子値を使用して同じ型のコレクションから選択できます。
@Autowired
は、注入時に自己参照 (つまり、現在注入されている Bean への参照) も考慮します。詳細については、自己注入を参照してください。
@Autowired
は、フィールド、コンストラクター、複数引数メソッドに適用され、パラメーターレベルで修飾子のアノテーションを絞り込むことができます。対照的に、@Resource
は、単一の引数を持つフィールドおよび Bean プロパティ setter メソッドに対してのみサポートされます。結果として、注入ターゲットがコンストラクターまたは複数引数メソッドである場合、修飾子を使用する必要があります。
独自のカスタム修飾子アノテーションを作成できます。これを行うには、次の例に示すように、アノテーションを定義し、定義内で @Qualifier
アノテーションを提供します。
Java
Kotlin
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {
String value();
}
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@Qualifier
annotation class Genre(val value: String)
次に、次の例に示すように、オートワイヤーされたフィールドとパラメーターにカスタム修飾子を提供できます。
Java
Kotlin
public class MovieRecommender {
@Autowired
@Genre("Action")
private MovieCatalog actionCatalog;
private MovieCatalog comedyCatalog;
@Autowired
public void setComedyCatalog(@Genre("Comedy") MovieCatalog comedyCatalog) {
this.comedyCatalog = comedyCatalog;
}
// ...
}
class MovieRecommender {
@Autowired
@Genre("Action")
private lateinit var actionCatalog: MovieCatalog
private lateinit var comedyCatalog: MovieCatalog
@Autowired
fun setComedyCatalog(@Genre("Comedy") comedyCatalog: MovieCatalog) {
this.comedyCatalog = comedyCatalog
}
// ...
}
次に、候補 Bean 定義の情報を提供できます。<qualifier/>
タグを <bean/>
タグのサブエレメントとして追加してから、type
および value
を指定して、カスタム修飾子アノテーションに一致させることができます。型は、アノテーションの完全修飾クラス名と照合されます。または、名前の競合のリスクが存在しない場合の便宜として、短いクラス名を使用できます。次の例は、両方のアプローチを示しています。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier type="Genre" value="Action"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier type="example.Genre" value="Comedy"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
クラスパススキャンと管理対象コンポーネントでは、XML で修飾子メタデータを提供する代わりのアノテーションベースの代替手段を見ることができます。具体的には、アノテーション付きの修飾子メタデータの提供を参照してください。
場合によっては、値なしでアノテーションを使用するだけで十分な場合があります。これは、アノテーションがより一般的な目的に役立ち、いくつかの異なる型の依存関係に適用できる場合に役立ちます。例: インターネットに接続できないときに検索できるオフラインカタログを提供できます。最初に、次の例に示すように、簡単なアノテーションを定義します。
Java
Kotlin
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {
}
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@Qualifier
annotation class Offline
次に、次の例に示すように、オートワイヤーするフィールドまたはプロパティにアノテーションを追加します。
Java
Kotlin
public class MovieRecommender {
@Autowired
@Offline (1)
private MovieCatalog offlineCatalog;
// ...
}
1 | この行は、@Offline アノテーションを追加します。 |
class MovieRecommender {
@Autowired
@Offline (1)
private lateinit var offlineCatalog: MovieCatalog
// ...
}
1 | この行は、@Offline アノテーションを追加します。 |
これで、次の例に示すように、Bean 定義には修飾子 type
のみが必要になります。
<bean class="example.SimpleMovieCatalog">
<qualifier type="Offline"/> (1)
<!-- inject any dependencies required by this bean -->
</bean>
1 | この要素は修飾子を指定します。 |
単純な value
属性に加えて、またはその代わりに、名前付き属性を受け入れるカスタム修飾子アノテーションを定義することもできます。オートワイヤーされるフィールドまたはパラメーターに複数の属性値が指定されている場合、Bean 定義は、オートワイヤーの候補と見なされるすべての属性値と一致する必要があります。例として、次のアノテーション定義を検討してください。
Java
Kotlin
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {
String genre();
Format format();
}
@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@Qualifier
annotation class MovieQualifier(val genre: String, val format: Format)
この場合、Format
は列挙型で、次のように定義されます。
Java
Kotlin
public enum Format {
VHS, DVD, BLURAY
}
enum class Format {
VHS, DVD, BLURAY
}
オートワイヤーされるフィールドには、カスタム修飾子でアノテーションが付けられ、次の例に示すように、両方の属性 genre
および format
の値が含まれます。
Java
Kotlin
public class MovieRecommender {
@Autowired
@MovieQualifier(format=Format.VHS, genre="Action")
private MovieCatalog actionVhsCatalog;
@Autowired
@MovieQualifier(format=Format.VHS, genre="Comedy")
private MovieCatalog comedyVhsCatalog;
@Autowired
@MovieQualifier(format=Format.DVD, genre="Action")
private MovieCatalog actionDvdCatalog;
@Autowired
@MovieQualifier(format=Format.BLURAY, genre="Comedy")
private MovieCatalog comedyBluRayCatalog;
// ...
}
class MovieRecommender {
@Autowired
@MovieQualifier(format = Format.VHS, genre = "Action")
private lateinit var actionVhsCatalog: MovieCatalog
@Autowired
@MovieQualifier(format = Format.VHS, genre = "Comedy")
private lateinit var comedyVhsCatalog: MovieCatalog
@Autowired
@MovieQualifier(format = Format.DVD, genre = "Action")
private lateinit var actionDvdCatalog: MovieCatalog
@Autowired
@MovieQualifier(format = Format.BLURAY, genre = "Comedy")
private lateinit var comedyBluRayCatalog: MovieCatalog
// ...
}
最後に、Bean 定義には一致する修飾子の値が含まれている必要があります。この例は、<qualifier/>
要素の代わりに Bean メタ属性を使用できることも示しています。可能な場合、<qualifier/>
要素とその属性が優先されますが、次の例の最後の 2 つの Bean 定義のように、そのような修飾子が存在しない場合、オートワイヤーメカニズムは <meta/>
タグ内で提供される値にフォールバックします。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier type="MovieQualifier">
<attribute key="format" value="VHS"/>
<attribute key="genre" value="Action"/>
</qualifier>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier type="MovieQualifier">
<attribute key="format" value="VHS"/>
<attribute key="genre" value="Comedy"/>
</qualifier>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<meta key="format" value="DVD"/>
<meta key="genre" value="Action"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<meta key="format" value="BLURAY"/>
<meta key="genre" value="Comedy"/>
<!-- inject any dependencies required by this bean -->
</bean>
</beans>