2017-12-12 18 views
1

내가 옳은지 잘 모르겠다면 CDI에서 Spring과 비슷한 것을 찾고있다. @ConditionalOnMissingBean - tell spring - 지정된 bean이없는 경우에만 만듭니다.다른 유형의 CDI 빈을 거부 할 경우

확장 프로그램을 사용해 보았습니다. 여러 이벤트를 탭하고 VETO 빈을 사용하는 것처럼 보입니다. 한 가지 방법은이 단계에서 BeanManager를 사용하고 이미 존재하는 빈을 찾은 다음 삽입 할 빈을 포함하는 경우이를 거부하는 것입니다. 그러나 이것은 우리가 모든 콩을 보았을 때만 작동 할 것입니다.

그러나 AfterBeanDiscovery가 호출되기 전에 유효성 검사가 실패하여 동일한 유형의 여러 빈을 불평합니다.

여기서 도움을 얻을 수 있다면 좋을 것입니다.

+0

내가 당신을 위해 무엇을 찾고있는 것은 우리가 CDI'Alternative'에 부르는 것을 믿습니다. 하지만 좀 더 잘 이해하고 싶습니다. 당신은 인터페이스'Interface1'을 가지고 있습니다. Bean으로 등록 된 다른 구현이없는 경우에만이 인터페이스의 구현을 설치하고 싶습니까? –

+0

예,이 컨텍스트에 "모호한 종속성"문제가있는 것과 같은 종류의 여러 bean을 가지는 것을 원하지 않습니다. 이미 컨텍스트에있는 같은 종류의 다른 bean이없는 경우에만 하나를 만들고 싶습니다. 있을 경우, 해당 제작자가 끼어 들지 않아야합니다. – karansardana

답변

0

당신의 질문은 흥미 롭습니다. 은 CDI 확장 기능을 사용하여 해결할 수 있습니다. 그것은 예를 들어 다루지 않기 때문에 순진하다. 생산자 방법/필드가 더 많이 누락 될 수 있습니다.

CDI 확장은 정말 훌륭하지만 강력하지만 오히려 기술적 일 수 있으므로 먼저 다른 대안을 논의 해 보겠습니다.

  1. 전문화 :

    @Specializes 
    public class SomeServiceSpecialImpl extends SomeServiceDefaultImpl {...} 
    
    :
    아마 사용 사례는 개발자가해야 할 public class SomeServiceDefaultImpl, 말을 통해 그것을 무시하기 위해 SomeService의 기본 구현을 제공 할 것을 명시 적으로 문서화하는 데 충분하다

    또한 John Ament의 의견에서 언급 한대로 대안을 고려하십시오.

  2. 예선 :이 서비스는 한 장소에서 사용하는 경우는/몇 군데 만 코드 내부에, 당신은 당신의 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(); 
        } 
    } 
    
  3. 을 강제하도록 @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"; 
        } 
    } 
    
    +0

    Nikos에 감사드립니다.이 유형의 것을 시도했지만 "조건부"주석이있는 버전을 거부하지 않았으므로 결국 afterBeanDiscovery 단계에 도달하기 전에 유효성 검사 오류가 발생했습니다. 내 부분에 나쁜 실수, 감사합니다, 니코. – karansardana

    +0

    전문화 및 한정어는 내가 원하는 것만 정확하게 작동 할 수 있습니다. 동일한 종류의 이미 존재하는 경우 컨텍스트에 특수화 된 bean을 원하지 않습니다. @Specialization을 사용하면 기존 데이터베이스를 무시할 것입니다 .- 케이스를 제공하지 않습니다. - 내 컨트롤이 아닌 라이브러리가없는 경우에만 존재하고 싶습니다. – karansardana