あなたの質問は面白くて、はで、CDI拡張機能を使って解くことができます。それは扱いにくいので素朴です。プロデューサのメソッド/フィールドがあり、それ以上見つからない可能性があります。
CDI拡張機能は本当に素晴らしく、強力ですが、むしろ技術的なことがありますので、最初に他の方法を検討してみましょう。
専門:
@Specializes
public class SomeServiceSpecialImpl extends SomeServiceDefaultImpl {...}
:多分あなたのユースケースは、あなたが開発者が行う必要がありますpublic class SomeServiceDefaultImpl
、たとえば、通って、それを上書きするために、SomeService
のデフォルトの実装を提供することを明示的に文書化するために十分です John Amentのコメントに記載されているように、代替案も検討してください。
修飾子:このサービスは一つだけの場所/いくつかの場所で使用され、唯一のあなたのコード内で、カスタム修飾子を使用して、あなたのSomeServiceDefaultImpl
を修飾することができれば、@MyDefaultImpl
を言います。その後、Instance<SomeService>
を注入最初の修飾されていないインスタンスを探し、それが満たされない場合は、資格を探して - の線に沿って何か:強制するように
private SomeService someService;
@Inject
void setSomeServiceInstance(Instance<SomeService> s) {
// not tried, please adapt as needed
if(s.isUnsatisfied()) {
someService = s.select(new MyDefaultImplAnnotation()).get();
}
else {
someService = s.get();
}
}
@Vetoed
あるデフォルトの実装を提供します実装を提供するコードのクライアント。クライアントがデフォルトを使用する場合、単にプロデューサを使用することができます。
以下の実装がコンセプトの証明である、上記の言った:
は、デフォルトの実装上に存在することが、次の注釈が必要です:
@Target({ TYPE, METHOD, FIELD })
@Retention(RUNTIME)
@Documented
public @interface ConditionalOnMissingBean {
Class<?> value();
}
value()
は必須で、「デフォルト」のBeanタイプを示します。あなたの実装はよりスマートになります。すなわち、実際のデフォルトの実装からBeanの型を検出しますが、それは概念の証明に過ぎません!
生産者を大いに無視します!
軽くテストされているので、おそらく邪悪なコーナーケースがあるので、注意してください!あなたが拡張(META-INF /サービス/ javax.enterprise.inject.spi.Extension、beans.xmlの)すべての振り付けを必要とするコードに加えて
。
import java.util.HashMap;
import java.util.Map;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanAttributes;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.InjectionTargetFactory;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
public class ConditionalOnMissingBeanExtension implements Extension {
private Map<Class<?>, AnnotatedType<?>> map = new HashMap<>();
<T> void processAnnotatedType(@Observes ProcessAnnotatedType<T> pat) {
AnnotatedType<?> annotatedType = pat.getAnnotatedType();
ConditionalOnMissingBean annotation = annotatedType.getAnnotation(ConditionalOnMissingBean.class);
if(annotation != null) {
map.put(annotation.value(), annotatedType);
pat.veto();
}
}
void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager beanManager) {
map.entrySet().stream()
.filter(e -> doesNotHaveBeanOfType(beanManager, e.getKey()))
.map(e -> defineBean(beanManager, e.getValue()))
.forEach(abd::addBean);
map = null;
}
private boolean doesNotHaveBeanOfType(BeanManager beanManager, Class<?> type) {
return beanManager.getBeans(type).isEmpty();
}
private <T> Bean<T> defineBean(BeanManager beanManager, AnnotatedType<T> annotatedType) {
BeanAttributes<T> beanAttributes = beanManager.createBeanAttributes(annotatedType);
InjectionTargetFactory<T> injectionTargetFactory = beanManager.getInjectionTargetFactory(annotatedType);
return beanManager.createBean(beanAttributes, annotatedType.getJavaClass(), injectionTargetFactory);
}
}
サービス・インターフェースのデフォルトの実装の例は次のようになります。
@ApplicationScoped
@ConditionalOnMissingBean(SomeService.class)
public class SomeServiceDefaultImpl implements SomeService {
@Override
public String doSomeCalculation() {
return "from default implementation";
}
}
私は何を探していることは、我々は 'Alternative' CDIに呼んでと考えています。しかし、私は少し良く理解したい。あなたはインターフェース 'Interface1'を持っています。 Beanとして登録されている他の実装がない場合にのみ、このインタフェースの実装をインストールしますか? –
はい、私はこのコンテキストに、その "あいまいな依存関係"につながる同じ種類の複数の豆を持たせたくありません。私は同じ種類の他のBeanがすでにコンテキスト内に存在しない場合にのみ、1つを生成したいと思います。存在していれば、そのプロデューサーは蹴らないでください。 – karansardana