2016-01-14 4 views
7

でのApplicationContextからBeanを取得します。このコードを考えると修飾子

public interface Service {} 

@Component 
@Qualifier("NotWanted") 
public class NotWantedService implements Service {} 

@Component 
@Qualifier("Wanted") 
public class WantedService implements Service {} 

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); 
ctx.register(NotWantedService.class); 
ctx.register(WantedService.class); 
ctx.refresh() 

どのように私は今やるん:だけ@Qualifier("Wanted")と1と@Qualifier("NotWanted")でないものを取得します方法で

ctx.getBean(Service.class) 

?私は具体的には、getBeanを使用してそれを行うことが可能かどうかを尋ねています。クラスに注入しないで、それを一種のプロキシとして使用します。

+0

名前の定数、つまり 'ctx.getBean(" Wanted ")'を使用しているので、名前でBeanを取得しないのはなぜですか? – aux

+0

@aux 'ctx.getBean(" service1 ")'を実行する場所が50あり、これを 'ctx.getBean(" service2 ")'に変更したいとします。それは50の変化です。修飾子を変更すると、2つのBean定義( 'service1'と' service2')のみに変更されます。他にも、「欲しい」複数の「サービス」インスタンスを取得したいとします。それらはすべて同じBean名を持つことはできません。 –

+0

OK、わかりました。そして、あなたのbeanへの参照を保持し、spring-data-restの 'Repositories'のような異なるパラメータによる参照に使用する独自の"レジストリ "Beanを導入するのはどうでしょうか?またはラッパービーンですか? – aux

答えて

7

ApplicationContext経由でBeanを取得するときにアノテーションを使用するのは、@Qualifierアノテーションの目的ではありません。しかし、何らかの理由でそのような機能や類似の機能が必要なので、私は回避策を提案します。

@Wanted@NotWanted注釈を作成します。

@Component 
@NotWanted 
public class NotWantedService implements Service {} 

:これらの新しい注釈を使用してBeanクラスに注釈を付ける

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, 
     ElementType.METHOD, ElementType.TYPE}) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface Wanted { 
} 

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, 
      ElementType.METHOD, ElementType.TYPE}) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface NotWanted { 
} 

をこのよう

ApplicationContext applicationContext; 

private <T> Collection<T> getBeansByTypeAndAnnotation(Class<T> clazz, Class<? extends Annotation> annotationType){ 
    Map<String, T> typedBeans = applicationContext.getBeansOfType(clazz); 
    Map<String, Object> annotatedBeans = applicationContext.getBeansWithAnnotation(annotationType); 
    typedBeans.keySet().retainAll(annotatedBeans.keySet()); 
    return typedBeans.values(); 
} 

private <T> Optional<T> getBeanByTypeAndAnnotation(Class<T> clazz, Class<? extends Annotation> annotationType) { 
    Collection<T> beans = getBeansByTypeAndAnnotation(clazz, annotationType); 
    return beans.stream().findFirst(); 
} 

をそして今、あなたはアノテーションで豆または1つのBeanを取得するためにそれらを使用することができますし、入力します:

@Component 
@Wanted 
public class WantedService implements Service {} 

あなたはApplicationContextへのアクセス権を持ってどこその後、あなたはどこかに2つの方法を追加する必要があります

Collection<Service> services = getBeansByTypeAndAnnotation(Service.class, Wanted.class); 

または

Service service = getBeanByTypeAndAnnotation(Service.class, Wanted.class); 

おそらくそれがBではありません問題に対処するための控えめな方法。しかし、我々は修飾子でApplicationContextから豆を得ることができないので、 'out of box'と入力してください。これはこれを行う方法の1つです。

+1

ありがとう@Rozart - 私はすでにそれを試みました。残念ながら、 '@修飾子 'は考慮されていません。これは '@Bean(name =" abc ")で指定されたbeanの名前を取ります。これは同じではありません。 –

+0

これは '@Bean(name =" abc ")と同じですが、同じセマンティクスはありません。あなたは同じ名前の2つの豆を持つことはできませんが、あなたは同じ資格を持つ複数の豆を持つことができます。つまり、「欲しい」と認定された10種類のサービスが必要ですが、「募集」とは言いません。 –

+0

私は答えを更新しました。多分それがあなたを助けるでしょう。 :) – Rozart

2

コンテキストからBeanを取得したい場合は、@ComponentアノテーションにBean名を定義し、コンテキストから名前を取得する方が良いでしょう。ほとんどの場合、@Qualifierは注射に使用されます。

1

春にこれを行うには、最も近い標準的な方法は、ユーティリティクラスBeanFactoryAnnotationUtilsである...しかし、これは悲しげにのみ(それゆえ、なぜ引数が文字列である)を直接@Qualifier注釈値の引数で動作します。

どのような@Rozart is recommendingが最良のアプローチであり、実際にはそれはBeanFactoryAnnotationUtilsにあるはずです。私は誰かがここに着陸し、直接@Qualifier(そしてそれに伴うすべてのBeanエイリアシング)を使用したい場合にのみ上記の答えを含めました。

私は春に機能リクエストを提出することをお勧めします(私は彼らが私に嫌になっていると思います:-))。

4

あなたは「qualifiedBeanOfType」メソッドのみConfigurableListenableBeanFactoryの修飾子を解決することができますので、それは、ctxctx.getBeanFactory()を使用するように、それ自体重要ではありません

BeanFactoryAnnotationUtils.qualifiedBeanOfType(ctx.getBeanFactory(), Service.class, "Wanted") 

を使用することができます。