Почему я не могу использовать @EJB с @Named?

В основном я пытаюсь внедрить bean-компонент @Stateless с локальным интерфейсом в класс, аннотированный с помощью @Named! Насколько я понимаю, инъекция возможна только тогда, когда точка инъекции управляется (имеет смысл), поэтому, например, было бы невозможно внедрить в POJO, но вы могли бы внедрить в сервлет, управляемый JSF или другой EJB.

Я бы подумал, что можно было бы впоследствии использовать его с @Named! Однако я получаю исключение NullPointerException, которое, по-видимому, подразумевает, что это на самом деле не кажется возможным!?

Мои классы выглядят так (раздеты для ясности);

@Named
public class EmailUtil {

// Logger-------------------------------------------------------------------
private static final Logger LOG = Logger.getLogger(EmailUtil.class.getName());

// Constructor--------------------------------------------------------------
public EmailUtil() {
}

// EJB----------------------------------------------------------------------
@EJB AuditDAO audit;

// Methods------------------------------------------------------------------
public void sendEmail(
        String emailSender,
        String emailRecipient,
        String emailSubject,
        String emailHtmlBody,
        String emailTextBody) throws FailedEmailException {

    ... code removed for clarity ...

    // Call Amazon SES to send the message 
    try {
        new SES().getClient().sendEmail(request);

        // Create an audit log of the event
        audit.create("Email sent to " + emailSender);
    } catch (AmazonClientException ace) {
        LOG.log(Level.SEVERE, ace.getMessage(), ace);
        throw new FailedEmailException();
    } catch (Exception e) {
        LOG.log(Level.SEVERE, e.getMessage(), e);
    }
}
}


@Stateless
public class AuditDAOImpl implements AuditDAO {

    // Logger-------------------------------------------------------------------
    private static final Logger LOG = Logger.getLogger(AuditDAOImpl.class.getName());
    // EntityManager------------------------------------------------------------
    @PersistenceContext(unitName = "iConsultPU")
    private EntityManager em;

    @Override
    public void create(String event) {
        String subject;
        try {
            /*
             * If the current subject has authenticated and created a session we
             * want to register their ID. However it is possible that a subject
             * does not have an ID so we want to set it to unknown.
             */
            subject = SecurityUtils
                    .getSubject()
                    .getPrincipals()
                    .asList()
                    .get(1)
                    .toString();
        } catch (Exception e) {
            subject = "UNKNOWN";
        }

        Audit audit = new Audit();
        audit.setUserId(subject);
        audit.setEventTime(Calendar.getInstance());
        audit.setEvent(event);

        em.persist(audit);

    }
}

@Local
public interface AuditDAO {
    public void create(String event);    
}

Я также пытался использовать @Inject, но это тоже не работает. Я неправильно понял спецификацию или просто плохо ее реализовал?


person tarka    schedule 21.06.2013    source источник
comment
Как получить доступ к своему классу? Куда внедряется EmailUtil?   -  person John Ament    schedule 21.06.2013
comment
Нет, проблема возникает из-за попытки внедрить компонент Audit EJB в EmailUtil.   -  person tarka    schedule 21.06.2013
comment
Если вы получите доступ к своему классу, выполнив инъекцию EmailUtil u = new EmailUtil(), это не сработает. Вот почему я хотел знать, как вы получаете к нему доступ.   -  person John Ament    schedule 21.06.2013
comment
Извини, Джон, я не знал, что это будет иметь эффект. Да, я вызываю новый EmailUtil с помощью конструктора. Итак, вы говорите, что невозможно вызвать класс с помощью конструктора, содержащего какие-либо инъекции?   -  person tarka    schedule 22.06.2013
comment
Это правильно. Если вам нужны какие-либо службы контейнера, вы должны позволить контейнеру создавать объекты.   -  person LightGuard    schedule 22.06.2013
comment
Имеет смысл! Не могли бы вы добавить это в ответ, когда у вас будет секунда, и я отмечу это как правильное.   -  person tarka    schedule 23.06.2013


Ответы (2)


Вы должны вводить свои зависимости. Поэтому, если ваш EmailUtil создается вручную, инъекция не сработает. Он должен управляться контейнером. Поэтому, если вы используете сервлет или любой управляемый компонент, вы можете @Inject его использовать. Внедрение CDI работает только для управляемых объектов.

Вы можете сделать некоторые дополнительные обходные пути, например вручную вызвать его для сконструированного экземпляра. Взгляните на этот вопрос для такого примера: Параллельные веб-службы доступ в среде Weld CDI

person John Ament    schedule 23.06.2013

У вас есть beans.xml в правильном месте? Внедрение для @Named (и других компонентов CDI) обрабатывается CDI, который не запускается, если у вас нет файла beans.xml в правильном месте (WEB-INF для войны и META-INF для jar).

person LightGuard    schedule 21.06.2013
comment
Да, мой beans.xml находится в WEB-INF. интересно то, что другие артефакты CDI, такие как @Inject, работают. В частности, @EJB это не так. Отсюда вопрос о том, есть ли что-то, чего я не понимаю в отношении использования @EJB. - person tarka; 22.06.2013