Dependency injection 如果存在另一个相同类型的CDIBean,则否决该CDIBean
我不确定我的想法是否正确,我正在[CDI]中寻找类似于Spring中的东西-@ConditionalOnMissingBean-这允许您告诉Spring-仅当指定的bean丢失时才创建 我尝试过使用扩展,看起来可以点击几个事件,并使用这些事件否决bean。一种方法可能是在这个阶段使用BeanManager,查找已经存在的bean,如果它包含您将要注入的bean,则否决这个bean。但是,这只有在我们查看了所有的bean之后才会起作用 然而,在beandiscovery看起来合适之后,在它被调用之前,验证失败,抱怨有多个相同类型的beanDependency injection 如果存在另一个相同类型的CDIBean,则否决该CDIBean,dependency-injection,cdi,Dependency Injection,Cdi,我不确定我的想法是否正确,我正在[CDI]中寻找类似于Spring中的东西-@ConditionalOnMissingBean-这允许您告诉Spring-仅当指定的bean丢失时才创建 我尝试过使用扩展,看起来可以点击几个事件,并使用这些事件否决bean。一种方法可能是在这个阶段使用BeanManager,查找已经存在的bean,如果它包含您将要注入的bean,则否决这个bean。但是,这只有在我们查看了所有的bean之后才会起作用 然而,在beandiscovery看起来合适之后,在它被调用之
如果我能在这里得到帮助就太好了 您的问题很有趣,可以使用CDI扩展来解决(实际上几乎与您描述的一样),请参见下面的简单、有效的概念验证实现。它是幼稚的,因为它不处理例如生产者方法/字段,并且可能缺少更多 CDI扩展确实很棒,功能强大,但是技术性很强,所以让我们先讨论其他替代方案
公共类SomeServiceDefaultImpl
提供SomeService
的默认实现,并且为了覆盖它,开发人员应该:
@Specializes
public class SomeServiceSpecialImpl extends SomeServiceDefaultImpl {...}
也考虑备选方案,如John Ament评论中提到的。
SomeServiceDefaultImpl
,例如@MyDefaultImpl
。然后注入一个实例
,首先查找一个不合格的实例,如果不合格,则查找合格的实例,如下所示:
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();
}
}
value()
是必需的,表示“默认”的bean类型。您的实现可以更智能,即从实际的默认实现中检测bean类型,但是,嘿,这只是一个概念证明我相信您正在寻找的是我们在CDI中所称的
替代方案
。但我想更好地理解。您有一个接口Interface1
。当且仅当没有其他实现注册为bean时,您才希望安装此接口的实现,对吗?是的,我不希望此上下文中有多个相同类型的bean,因为这会导致“不明确的依赖关系”之类的事情。我只想在上下文中没有其他同类bean的情况下生成一个。如果有,制作人不应该插手。感谢Nikos,我想我也尝试过这种类型的东西,但没有否决带有“条件”注释的,因此,在我到达后Beandiscovery阶段之前就出现了验证错误。我犯了一个错误,非常感谢,Niko。专门化和限定符可以工作,但是,这并不完全是我想要的——如果已经存在相同类型的专门化bean,我不希望上下文中出现专门化bean。有了@Specialization,我将用我的来覆盖现有的-不适用于这种情况-我只希望我的存在存在于没有任何其他(超出我的控制范围-我的是一个库)的情况下。
@Target({ TYPE, METHOD, FIELD })
@Retention(RUNTIME)
@Documented
public @interface ConditionalOnMissingBean {
Class<?> value();
}
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";
}
}