我正在編寫一個在Tomcat上運行的CDI應用程序。我使用Tomcat 7.0.62和 Weld 2.2.12.Final作爲CDI實現。我在沒有JSF的情況下使用CDI。包含啓用CDI的Servlet因ContextNotActiveException失敗:WELD-001303:
該應用程序由不啓用CDI的調度程序servlet組成。 調度程序包含啓用CDI的servlet的輸出以創建頁面。
當調度程序servlet和CDI servlet都在同一個web應用程序中時, 工作正常。不過,我需要CDI servlet在不同的web應用程序中,所以我做了一個跨環境包含。當我執行跨環境包含時,CDI servlet 會生成輸出,直到它嘗試訪問@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的調度程序servlet的爲好,但它似乎並不 任何區別。
在我看來,像包含CDI servlet的CDI servlet的請求上下文沒有正確設置 ,而不是直接接收請求 。
我已經搜索過這個網站,也通過谷歌,但還沒有找到匹配的 問題/解決方案。我發現我應用於調度程序servlet的tomcat上下文設置'fireRequestListenersOnForwards =「true」' ,但這沒有什麼不同。
這是一個配置問題嗎?任何人都可以提供關於如何解決這個問題的線索嗎?
我將不勝感激!
背景資料:
有問題的實際應用是大的,所以我凝結下來獲得 到破碎的精髓。結果,我有兩個戰爭檔案。第一個war文件 包含CDI servlet和調度程序(在我稱之爲includer的代碼中)servlet。第二個war文件僅包含 調度程序servlet。
的CDI的Servlet
的CDI的Servlet有以下內容在其META_INF目錄中的context.xml文件:
<?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>
的CDI servlet的web.xml文件中包含行:
<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>
CDI Servlet WEB-INF目錄包含一個beans.xml文件。
的CDI的servlet自舉豆執行通過使用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());
}
}
的包入(分派)的Servlet
的包入servlet有一個在其META-INF目錄中的context.xml文件:
<?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 DER servlet查找的CDI的servlet上下文並獲得 的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的servlet URI:本地主機:8080/SimpleCDIServlet/CDIServlet我得到預期的輸出:
Simple CDI Servlet
finally here we are. Name is: InjectedBean
如果我通過位於相同的Web應用程序的調度程序servlet的訪問CDI的servlet CDI servlet,它也可以工作。 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的servlet,我不輸出獲得注入的bean的名字和異常上面提到的是在日誌中。 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請求效率不高,因爲請求數 將乘以包含的servlet的數量,並且除此之外,這將是相當難看的 。
更新: 我想這一點上Tomee 1.7.2,並在WebSphere Application Server V8.5。結果總結如下。
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
我越思考這個,我越覺得它真的應該工作。您應該能夠 成功地使用請求分派器在Tomcat上包含啓用CDI的servlet的輸出。 我希望這裏的某個人能幫我弄清楚如何使它工作。
什麼是...?你如何真正獲得你的CDIServlet生成的內容?其次:你能直接從瀏覽器(或HttpRequester工具)而不是通過前端控制器調用servlet嗎?這是否成功? – Gimby
嗨Gimby,謝謝你的迴應。我擴展了代碼片段並添加了程序輸出文本。如果我直接訪問CDI servlet,它就可以工作。如果我通過位於與CDI portlet相同的Web應用程序的調度程序servlet訪問CDI servlet,它也可以工作。它失敗當我嘗試從不同的上下文中包含servlet時。 –
好問題。實際上,當交叉環境包含完成時,CDI/Weld沒有機會初始化自己。這實際上並不令我感到奇怪,因爲在這種情況下,CDIServlet將不會涉及實際的HTTP請求,因此CDI偵聽器甚至可能不會觸發。技術解決方法:對第二個servlet執行HTTP請求,但我想知道是否有適當的解決方案。 – Gimby