2015-06-03 5 views
2

Я пишу приложение CDI, которое работает на Tomcat. Я использую Tomcat 7.0.62 с Weld 2.2.12.Final как реализация CDI. Я использую CDI без JSF.Включенный сервлет с поддержкой CDI с ContextNotActiveException: WELD-001303:

Приложение состоит из сервлета диспетчера, который не поддерживает CDI. Диспетчер включает в себя вывод сервлета с поддержкой CDI для создания страницы.

Когда сервлет диспетчера и сервлет CDI находятся в одном и том же веб-приложении, работает нормально. Тем не менее, мне нужен сервлет CDI для работы в другом веб-приложении, поэтому Я использую кросс-контекст. Когда я включаю кросс-контекст, сервлет CDI производит выходные данные, пока не попытается получить доступ к компоненту @RequestScoped. Bean доступа не за исключением следующего:

org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped 
    at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:708) 
    at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:90) 
    at org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:165) 
    at org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:63) 
    at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:83) 
... 

Я попытался активации КДИ для диспетчера сервлета, а также, но это, похоже, не делать никакой разницы.

Мне кажется, что контекст запроса для сервлета CDI не настроен должным образом, когда сервлет CDI включен в отличие от приема запроса напрямую.

Я искал этот сайт, а также через Google, но не нашел подходящую проблему/решение . Я нашел параметр контекста tomcat «fireRequestListenersOnForwards =« true »' , который я применил к сервлету диспетчера, но это не повлияло.

Это проблема конфигурации? Может ли кто-нибудь дать понять, как это решить?

Буду очень признателен вам!


Справочная информация:

Фактическое применение имеющих проблемы большой, поэтому я конденсируется его вниз, чтобы получить к сущности разбитости. В результате у меня есть два военных файла. Первый файл войны содержит сервлет CDI и диспетчер (в коде, который я назвал его включенным). Второй файл войны содержит только сервлет диспетчера.

ИПР Servlet

ИПР Servlet есть файл context.xml в своей директории META_INF со следующим содержанием:

<?xml version="1.0" encoding="UTF-8"?> 
<Context> 
    <Resource name="BeanManager" 
     auth="Container" 
     type="javax.enterprise.inject.spi.BeanManager" 
     factory="org.jboss.weld.resources.ManagerObjectFactory" /> 
</Context> 

Файл сервлет web.xml CDI содержит строки:

<listener> 
    <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class> 
</listener> 

<resource-env-ref> 
    <resource-env-ref-name>BeanManager</resource-env-ref-name> 
    <resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type> 
</resource-env-ref> 

В каталоге WEB-INF для сервлетов CDI содержится файл beans.xml.

ИПР сервлетные бутстрап исполнение фасоли посредством использования BeanManager получены через JNDI поиск (это работает):

BeanManager bm = null; 
try { 
    InitialContext context = new InitialContext(); 

    try { 
     // "regular" naming 
     bm = (BeanManager) context.lookup("java:comp/BeanManager"); 
    } catch(NameNotFoundException e) { 
     // try again with Tomcat naming 
     bm = (BeanManager) context.lookup("java:comp/env/BeanManager"); 
    } 
} catch (Exception e) {} 

if (bm == null) { 
    writer.write("Couldn't look up the bean manager"); 
} else { 
    Set<Bean<?>> beans = bm.getBeans(EnclosingBean.class); 
    @SuppressWarnings("unchecked") 
    Bean<EnclosingBean> bean = (Bean<EnclosingBean>) bm.resolve(beans); 
    if (bean == null) { 
     writer.write("Couldn't get the bean"); 
    } else { 
     EnclosingBean eb = (EnclosingBean) bm.getReference(bean, bean.getBeanClass(), bm.createCreationalContext(bean)); 
     writer.write("finally here we are. Name is: "); 
     writer.write(eb.getName()); 
    } 
} 

The (грузоотправитель) сервлет Includer

includer сервлет имеет context.xml в каталоге META-INF:

<?xml version="1.0" encoding="UTF-8"?> 
<Context 
    path="/ExternalIncluderServlet" 
    docBase="ExternalIncluderServlet.war" 
    crossContext="true" 
    fireRequestListenersOnForwards="true"> 

    <Resource name="BeanManager" 
     auth="Container" 
     type="javax.enterprise.inject.spi.BeanManager" 
     factory="org.jboss.weld.resources.ManagerObjectFactory" /> 
</Context> 

Inclu дер сервлет смотрит контекст КДИ сервлета и получает RequestDispatcher следующим образом (это работает):

ServletContext sc = request.getServletContext(); 
ServletContext extsc = sc.getContext("/SimpleCDIServlet"); 
if (extsc == null) { 
    writer.println("<p>Couldn't get the external context.</p>"); 
} else { 

    RequestDispatcher rd = extsc.getRequestDispatcher("/CDIServlet"); 
    if (rd == null) { 
     writer.println("<p>RequestDispatcher is null.</p>"); 
    } else { 
     writer.println("<p>Got the RequestDispatcher.</p>"); 
     rd.include(req, resp); 
    } 
} 

Результаты:

Когда я использую браузер для доступа к CDI сервлета непосредственно через URI: локальный: 8080/SimpleCDIServlet/CDIServlet Я получаю ожидаемый результат:

Simple CDI Servlet 
finally here we are. Name is: InjectedBean 

Если я получить доступ к CDI сервлет через диспетчерскую сервлета, расположенный в том же веб-приложение, что и CDI, он также работает. URI:/SimpleCDIServlet/IncluderServlet, выход:

Simple CDI Servlet Including Servlet 
Will now include the CDI servlet ... 
Got the RequestDispatcher. 
Simple CDI Servlet 
finally here we are. Name is: InjectedBean 

Но если я включаю CDI сервлет из другого контекста, я не получаю впрыскиваемого имя боба на выходе и исключение было отмечено выше в журнале. URI:/ExternalIncluderServlet/IncluderServlet, выход:

CDI Servlet Includer 

This servlet includes a CDI servlet in a different web app. It is not CDI enabled. 

Got the RequestDispatcher. 
Simple CDI Servlet 
finally here we are. Name is: 

Обратите внимание, что я не могу использовать диспетчер запросов вперед вместо того, чтобы включать в себя как оригинальный приложение включает в себя вывод из нескольких других сервлетов, а не только один. И открытие нового HTTP-запроса для каждого из них будет неэффективным, так как количество запросов будет умножено на количество включенных сервлетов, и это будет довольно уродливо .


Update: Я попробовал это на Tomee 1.7.2, а также на версии 8.5 WebSphere Application Server. Результаты приведены ниже.

 
          WAS 8.5   Tomcat 7.0.62   Tomee 1.7.2 
          =======   =============   =========== 
CDI servlet direct access works    works     works 

Included by servlet   works    works     works   
    in same web app 

Included by servlet   works    broken     broken 
    in different web app 

Чем больше я думаю об этом, тем больше я чувствую, что это действительно должно работать. Вы должны иметь возможность успешно использовать диспетчер запросов для включения вывода с сервлета с поддержкой CDI на Tomcat. Я надеюсь, что кто-то здесь может помочь мне разобраться, как заставить его работать.

+0

А что на ...? Как вы фактически получаете контент, созданный вашим CDIServlet? Во-вторых: можете ли вы вызвать сервлет непосредственно из браузера (или инструмента HttpRequester), а не через фронт-контроллер? Успешно ли это работает? – Gimby

+0

Привет, Гимби, Спасибо за ваш ответ. Я расширил фрагмент кода, а также добавил текст вывода программы. Если я напрямую обращаюсь к сервлету CDI, он работает. Он также работает, если я получаю доступ к сервлету CDI через сервлет диспетчера, расположенный в том же веб-приложении, что и портлет CDI. Это не удается. Когда я пытаюсь включить сервлет из другого контекста. –

+0

Хороший вопрос. По сути, CDI/Weld не получает возможности инициализировать себя, когда кросс-контекст включен. Это на самом деле не кажется мне чем-то странным, так как в этом случае в CDIServlet не будет никакого фактического HTTP-запроса, чтобы слушатель CDI даже не стрелял. Техническое решение: выполните запрос HTTP ко второму сервлету, но мне интересно, есть ли для этого правильное решение. – Gimby

ответ

4

WOW! с помощью хорошего друга я получил его!

Для выполнения этой работы вам необходимо настроить специальный фильтр кросс-контекста Weld. Вы настраиваете фильтр, добавляя следующие строки в файл web.xml.

<filter> 
    <filter-name>WeldCrossContextFilter</filter-name> 
    <filter-class>org.jboss.weld.servlet.WeldCrossContextFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>WeldCrossContextFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
    <dispatcher>INCLUDE</dispatcher> 
    <dispatcher>FORWARD</dispatcher> 
    <dispatcher>ERROR</dispatcher> 
</filter-mapping> 

Когда я настраиваю это, кросс-контекстное включение сервлета CDI работает должным образом. Я пробовал это на Tomcat 7.0.42 и 8.0.23 и до сих пор, так хорошо.

Смотрите также:

http://javadox.com/org.jboss.weld/weld-core-impl/2.2.4.Final/org/jboss/weld/servlet/WeldCrossContextFilter.html

Я искал ссылку на фильтр в официальной документации Weld, но не смог найти что-нибудь. Во всяком случае, я надеюсь, что это может помочь кому-то.

 Смежные вопросы

  • Нет связанных вопросов^_^