CDI: внедрение одного экземпляра работает, а внедрение экземпляра‹› — нет. Почему?

Я пытаюсь реализовать что-то вроде «функции плагина» с помощью инъекции CDI. Но у меня возникли некоторые проблемы, и я подумал, что могу узнать мнение со стороны от моих товарищей «Стэкеров» :-)

Я дошел до того, что что-то вроде этого работает:

@Inject 
@ScoringModule("AGE")
private AgeModule ageModule;

@Inject 
@ScoringModule("CUSTOMER_TYPE")
private CustomerTypeModule customerTypeModule;

Когда я "запускаю" это, оба поля вводятся с соответствующими экземплярами. Но когда я пытаюсь ввести их немного более «динамично», вот так:

@Inject @Any
private Instance<CustomerScoringModule> scoringModuleInstance;

CustomerScoringModule module = scoringModuleInstance.select(new ScoringModuleLiteral("AGE")).get();

Тогда я получу такое исключение:

org.jboss.weld.exceptions.UnsatisfiedResolutionException: WELD-001334: Unsatisfied dependencies for type CustomerScoringModule with qualifiers @Any @ScoringModule

Мне это кажется странным, потому что CDI явно «знает» об интересующих меня экземплярах, потому что работает прямая инъекция в типизированные поля. Я предполагаю, что это должно иметь какое-то отношение к квалификаторам? Каким-то образом CDI «видит» эти два экземпляра, но решает, что ни один из них не подходит для моего запроса на инъекцию? это может быть?

Есть ли что-нибудь «очевидное», что приходит на ум, что я могу делать неправильно здесь? Я пытаюсь использовать CDI в первый раз, и возможно (или даже вероятно), что я где-то делаю что-то глупое :-)

Любая помощь или подсказка приветствуются и заранее большое спасибо!

Ниже я прикреплю «окружающие» классы для квалификатора, литерала аннотации и так далее для справки.

Интерфейс CustomerScoringInterface, реализуемый обоими модулями:

package de.otto.cccs.customerscoring.modules;

import de.otto.cccs.customerscoring.modules.vo.ScoringModuleResponseVO;
import de.otto.cccs.customerscoring.valueobjects.webservice.ScoringRequestVO;

public interface CustomerScoringModule {
    public ScoringModuleResponseVO process(ScoringRequestVO inputVO);
}

Одна из двух реализаций модуля (сейчас это всего лишь фиктивные реализации, и единственная разница заключается в выводе log.info() в методе process(), поэтому я включил здесь только одну из них):

package de.otto.cccs.customerscoring.modules;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;

import de.otto.cccs.customerscoring.modules.qualifiers.ScoringModule;
import de.otto.cccs.customerscoring.modules.vo.ScoringModuleResponseVO;
import de.otto.cccs.customerscoring.valueobjects.webservice.ScoringRequestVO;
import lombok.extern.log4j.Log4j2;

@Log4j2
@Stateless
@LocalBean
@ScoringModule("AGE")
public class AgeModule implements CustomerScoringModule {

    public AgeModule() {
        super();
    }

    @Override
    public ScoringModuleResponseVO process(ScoringRequestVO inputVO) {
        log.info("processed AGE_MODULE");

        return new ScoringModuleResponseVO();
    }

}

Квалификатор @ScoringModule:

package de.otto.cccs.customerscoring.modules.qualifiers;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface ScoringModule {
    String value();
}

И AnnotationLiteral:

package de.otto.cccs.customerscoring.modules.qualifiers;

import javax.enterprise.util.AnnotationLiteral;

public class ScoringModuleLiteral extends AnnotationLiteral<ScoringModule> implements ScoringModule {

    private static final long serialVersionUID = 1L;
    private String value;

    public ScoringModuleLiteral(String value) {
        this.value = value;
    }

    @Override
    public String value() {
        return this.value;
    }
}

И, наконец, мой пустой файл beans.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

person Mario Köhler    schedule 16.08.2017    source источник
comment
Я вижу, что прямые инъекции используют точный тип bean-компонента, а не интерфейс. @Inject @ScoringModule("AGE") CustomerScoringModule ageModule работает?   -  person Nikos Paraskevopoulos    schedule 16.08.2017
comment
это справедливое замечание и хороший вопрос. Я сейчас не на работе, но завтра проверю и отчитаюсь. Спасибо за ваш отзыв.   -  person Mario Köhler    schedule 16.08.2017
comment
блин ... не мог ждать до завтра, должен был знать, работает это или нет :-) только что проверил удаленно через TeamViewer и протестировал его, и он НЕ работает, когда я использую интерфейс, как вы предложили. Вопрос в том, что это нам говорит?   -  person Mario Köhler    schedule 16.08.2017
comment
Может быть, интерфейсу тоже нужен какой-то квалификатор? Я попытался поместить @ScoringModule() в интерфейс CustomerScoringModule, но это тоже не сработало.   -  person Mario Köhler    schedule 16.08.2017
comment
Что это нам говорит - не знаю. Это отправная точка. Как упаковано приложение? Все эти классы в одной банке? Может быть, CDI (или EJB???) не распознает CustomerScoringModule как локальный бизнес-интерфейс, поэтому он не включен в типы bean-компонентов CDI? Что произойдет, если вы опустите @LocalBean (если это вообще возможно)?   -  person Nikos Paraskevopoulos    schedule 16.08.2017
comment
Вы можете быть на что-то. Я просто использовал ATLocalBean по привычке, не задумываясь о том, что эта аннотация подразумевает, что компонент не реализует явный бизнес-интерфейс. Завтра попробую ATLocal. Я также сомневаюсь в своем решении, действительно ли модули должны быть EJB или я могу использовать POJO. Сначала я не был уверен, смогу ли я использовать внедрение CDI с не-EJB-классами, но теперь я прочитал, что это ограничение было снято с недавним выпуском J2EE. Так что есть пара вещей, которые я могу попробовать завтра. Пока спасибо за пищу для размышлений, отчитаюсь.   -  person Mario Köhler    schedule 16.08.2017
comment
Да, используйте простые компоненты CDI (а не EJB), если они вам действительно не нужны.   -  person Nikos Paraskevopoulos    schedule 16.08.2017


Ответы (1)


В итоге я заменил модули EJB на простые классы Java, и все мои проблемы исчезли.

Мне действительно не нужно было, чтобы модули были EJB, я просто ошибочно предположил в начале, что они должны быть введены через CDI, что больше не так (это было верно для более старых выпусков J2EE)

Спасибо за ответ!

person Mario Köhler    schedule 17.08.2017
comment
современная философия CDI в порядке, это большой прогресс с древних времен и очень привлекательная, например. для весенних пользователей. редактировать: многие источники знаний смешивают J2EE, spring и т. д. Мое личное средство - чистый CDI - person Jacek Cz; 20.08.2017