당신의 질문은 흥미 롭습니다. 은 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 유형을 감지 할 수 있습니다. 그러나 이것은 개념 증명 일뿐입니다!
뻔뻔스럽게 생산자를 무시하십시오!
가볍게 테스트되었으므로 악의적 인 코너 케이스가있을 수 있으므로 BEWARE! 당신이 확장 (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";
}
}
내가 당신을 위해 무엇을 찾고있는 것은 우리가 CDI'Alternative'에 부르는 것을 믿습니다. 하지만 좀 더 잘 이해하고 싶습니다. 당신은 인터페이스'Interface1'을 가지고 있습니다. Bean으로 등록 된 다른 구현이없는 경우에만이 인터페이스의 구현을 설치하고 싶습니까? –
예,이 컨텍스트에 "모호한 종속성"문제가있는 것과 같은 종류의 여러 bean을 가지는 것을 원하지 않습니다. 이미 컨텍스트에있는 같은 종류의 다른 bean이없는 경우에만 하나를 만들고 싶습니다. 있을 경우, 해당 제작자가 끼어 들지 않아야합니다. – karansardana