Почему Weld говорит, что внедрение в слушателей не поддерживается на Tomcat?

У меня есть веб-проект, использующий Resteasy (который, в свою очередь, использует Weld), и он развернут на Tomcat 7.0.22 (здесь я помещаю конкретную версию на случай, если эта проблема связана с этой версией).

У меня есть ServletContextListener, который выглядит так:

@WebListener
public class ApplicationInitialisationListener implements ServletContextListener {
    // create a logger here        

    @Inject
    HealthCheck healthCheck;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        if (healthCheck == null) {
            log.error("healthCheck is null");
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
    }
}

После развёртывания на Tomcat логировалось healthCheck is null, и ещё я заметил в логе эту строчку:

<2013-11-13 13:27:40,191> <pack> INFO pool-2-thread-1 org.jboss.weld.environment.tomcat7.Tomcat7Container - Tomcat 7 detected, CDI injection will be available in Servlets and Filters. Injection into Listeners is not supported

Вопрос 1: почему внедрение CDI недоступно в прослушивателях?

Я просмотрел этот ответ, и он говорит Load on startup via @Startup. There is currently no equivalent to this in CDI.

Вопрос 2: является ли проблема, описанная в вопросе 1, следствием этого?

Вопрос 3. Я использую org.jboss.weld.servlet:weld-servlet:1.2.0.Beta1. Есть ли какие-либо обновления по поддержке запуска в более поздних версиях?

Похожие вопросы, которые я просмотрел стартовый класс в Weld


person stackoverflower    schedule 13.11.2013    source источник
comment
Что касается вопроса 3: обратите внимание, что в сообщении говорится, что он не поддерживается CDI, то есть спецификация CDI не определяет это. Это может быть добавлено в будущую версию и, следовательно, в любую версию Weld, которая реализует эту будущую версию CDI.   -  person Thomas    schedule 13.11.2013
comment
@Thomas CDI не относится к сервлетам, поэтому он не будет определять ничего, связанного с внедрением в среду Java EE. Это сварной шов и элемент JSR 299.   -  person Sotirios Delimanolis    schedule 13.11.2013
comment
@SotiriosDelimanolis ах, да, ты прав. ооооо :)   -  person Thomas    schedule 14.11.2013


Ответы (3)


Вот обходной путь, который я обнаружил, который может внедрять компоненты CDI при запуске приложения.

Требование задачи можно сформулировать так:

  1. внедрить компонент CDI при запуске приложения
  2. сделать что-нибудь с фасолью

Строка контура решения:

  1. Создайте WebListener, который вызывает BeanManager.fireEvent(new SomeDummyEvent())
  2. Создайте bean-компонент ApplicationScoped, который отвечает на SomeDummyEvent и внедряет bean-компонент CDI.

Пример кода:

@WebListener
public class ApplicationInitialisationListener implements ServletContextListener {
    private static final Logger LOG = Logger.getLogger(ApplicationInitialisationListener.class);

    @Override
    public void contextInitialized(ServletContextEvent event) {
        BeanManager beanManager = lookUpBeanManager();
        if (beanManager != null) {
            beanManager.fireEvent(new SomeDummyEvent());
            LOG.info("beanManager fired SomeDummyEvent.");
        } else {
            LOG.error("beanManager is null.  Cannot fire startup event.");
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
    }

    public BeanManager lookUpBeanManager() {
        try {
            // See reference below about how I came up with this
            InitialContext iniCtx = new InitialContext();
            BeanManager result = (BeanManager) iniCtx.lookup("java:comp/env/BeanManager");
            return result;
        } catch (NamingException e) {
            LOG.error("Could not construct BeanManager.", e);
            return null;
        }
    }

    public static class SomeDummyEvent implements Serializable {
    }
}

@ApplicationScoped
public class InitializationResourceBean {

    private static final Logger LOG = Logger.getLogger(InitializationResourceBean.class);

    @Inject
    HealthCheck healthCheck;

    public void listen(@Observes ApplicationInitialisationListener.SomeDummyEvent event) {
    }

    @PostConstruct
    public void init() {
        // Do something with healthCheck
    }

    @PreDestroy
    public void destroy() {
        // Do some other thing with healthCheck
    }
}

Использованная литература:

http://struberg.wordpress.com/tag/cdi/

person stackoverflower    schedule 21.11.2013

Из: http://docs.jboss.org/weld/reference/latest-master/en-US/html/environments.html#_tomcat

«Поддерживаются Tomcat 7 и 8. Активация/деактивация контекста и внедрение зависимостей в сервлеты и фильтры работают из коробки. Внедрение в прослушиватели сервлетов работает на Tomcat 7.0.50 и новее».

Так что, возможно, вы можете обновить свой Tomcat?

person matsa    schedule 16.09.2015

Теперь все это очень легко сделать с модулем сервлета deltaspike.

@ApplicationScoped
public class InitializationResourceBean {

 @Inject
 HealthCheck healthCheck;

  public void onCreate(@Observes @Initialized ServletContext context) {
    //Do initialisation stuff here.
    if(HealthCheck != null) {
      ;
    }
  }
  public void onDestroy(@Observes @Destroyed ServletContext context) {
    System.out.println("Destroyed ServletContext: " + context.getServletContextName());
  }

}

http://deltaspike.apache.org/documentation/servlet.html

person temaleva    schedule 20.02.2014