[英]@EJB annotation does not work for initialize bean within the EJB application
我有一個具有以下結構的Maven項目:
-myproject
-myproject-ear
-myproject-service
-webservice
-myproject-ejb
在myproject-ejb
我有以下java軟件包:
-src/main/java/
-src/test/java/
我有一個EJB和相應的bean實現
-src/main/java/org/mypackage/MyBean.java
-src/main/java/org/mypackage/MyBeanImpl.java
在src/test/java/
我有一個名為MyBeanTest.java的測試,代碼如下:
import javax.ejb.EJB;
import org.mypackage.MyBean;
import org.junit.*;
public class MyBeanTest {
@EJB
private MyBean myBean;
@Test
public void testBean() {
System.out.println("myBean: "+myBean); // prints null
myBean.writeToDB("Hello", "World"); // fails since myBean is null
}
}
當我運行單元測試時, myBean
為空。 我想知道為什么@EJB
注釋不起作用。 測試包與Bean在同一應用程序中,因此@EJB
應該可以工作。
有任何想法嗎?
編輯1
我發現此鏈接與我遇到的問題相同,但是那里的解決方案似乎對我不起作用。 我做錯什么了嗎?
package org.myproject.ejb;
import java.util.Hashtable;
import java.util.Properties;
import javax.ejb.EJB;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import org.myproject.ejb.MyBean;
import org.jboss.ejb.client.ContextSelector;
import org.jboss.ejb.client.EJBClientConfiguration;
import org.jboss.ejb.client.EJBClientContext;
import org.jboss.ejb.client.PropertiesBasedEJBClientConfiguration;
import org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector;
import org.junit.*;
public class MyBeanTest {
private MyBean myBean;
@Before
public void init() {
try {
Properties clientProp = new Properties();
clientProp.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
clientProp.put("remote.connections", "default");
clientProp.put("remote.connection.default.port", "4447");
clientProp.put("remote.connection.default.host", "localhost");
clientProp.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");
EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(clientProp);
ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc);
EJBClientContext.setSelector(selector);
Properties env = new Properties();
env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
env.put(Context.SECURITY_PRINCIPAL, "admin");
env.put(Context.SECURITY_CREDENTIALS, "testing");
InitialContext ctx = new InitialContext(env);
myBean = (MyBean) ctx.lookup("java:app/myproject-ejb-1.0-SNAPSHOT/MyBeanImpl");
}
catch(NamingException ex) {
ex.printStackTrace();
}
}
@Test
public void testBean() {
System.out.println("ejb: "+myBean); // prints null
}
}
我在上面的配置中得到的錯誤是:
WARN: Unsupported message received with header 0xffffffff
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:662)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:307)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:344)
容器資源注入(例如@EJB)需要一個已填充的JNDI目錄,並且只能在Java EE容器中執行的Java EE受管組件內工作。 對於單元測試是一個挑戰。 請參閱JSR318 Java EE 6平台規范,第EE.5節“資源,命名和注入”。
您現在正在嘗試JNDI查找-Java SE單元測試應用程序遠程連接其JNDI上下文。 缺點:必須部署完整的Java EE 6應用作為運行測試的前提; test-bugfix-build-deploy-retest生命周期可能會使事情變慢。
一些問題:
"ejb:..."
而不是"java:app/..."
因為JBoss EJB客戶端項目代碼使用此名稱來攔截查找。 同樣來自Java EE 6平台規范EE.5.2.2: java:app
命名空間中的名稱由單個Java EE應用程序中所有模塊中的所有組件共享。 如果您的測試是使用java:app
的單獨的JSE應用java:app
,則我懷疑JBoss將其視為與單個Java EE應用程序分開的應用程序,並且查找將失敗。 嘗試以下操作:
包括以下屬性:
clientProp.put("remote.connection.default.username", "admin"); clientProp.put("remote.connection.default.password", "testing");
更改客戶參考:
java:app/myproject-ejb-1.0-SNAPSHOT/MyBeanImpl to ejb:<app-ear-name>/<module-jar-name>/<jboss-optional-distinct-name>/<bean-name>!<fully-qualified-classname-of-the-remote-interface>
例如,如果MyBean是部署在myproject-ejb-1.0-SNAPSHOT.jar中的無狀態EJB(無需任何注意)。 然后:
ejb:/myproject-ejb-1.0-SNAPSHOT//MyBeanImpl!org.mypackage.MyBean
如果它是有狀態的EJB,則在字符串中添加“?stateful”。
直接(通過文件或程序)設置ejb-client.properties
直接應用於JNDI Context
。 參見https://docs.jboss.org/author/display/AS72/EJB+invocations+from+a+remote+client+using+JNDI和https://docs.jboss.org/author/display/AS72/Scoped + EJB + client +上下文和http://middlewaremagic.com/jboss/?p=1177
將來:使用CDI進行注射; JUnit + CDI @Mock
用於“ POJO”單元測試; Arquillian,用於在容器中進行“ Java EE”單元/模塊測試。 然后,您可以避免/減少上述(2)的測試(JSE客戶端-> EJB)。 CDI支持:
@EJB
注釋)。 這仍然需要已部署的Java EE應用程序/組件和已填充的JNDI目錄才能進行查找。 作為POJO或Java EE組件(包括EJB)的托管bean-使用高級@Inject注釋將“ any”注入“ any”。 可在沒有JNDI目錄的情況下使用,是類型安全的和bean作用域感知的。
通過簡單的模擬支持單元測試。 使用@Mock
和@Specializes
聲明任何bean的替換版本。 在沒有EJB的情況下測試EJB客戶端。 將EJB作為POJO進行測試。
要啟用CDI,請包含beans.xml
文件(如果全部通過注釋進行配置,則可以為空)。
聲明托管bean:
@SessionScoped
@Inject
使用它來注入參考:
@Inject (optional @MyDeclaredQualifier) private MyBean myBean;
Arquillian (“ JUnit for Java EE 6”)本身在Java EE服務器上運行測試代碼。 它動態地將測試代碼部署到已配置的容器並運行測試。 它支持@EJB注釋,JNDI連接變得簡單,您可以在單元測試中包括Java EE類,而無需進行模擬或重構以將其抽象化。
1)注解注入是通過容器完成的。 因此,非托管類(容器托管)將無法進行注解注入。
2)現在,在這種情況下,您將必須手動調用JNDI並檢索EJB實例:
即:
InitialContext ctx = new InitialContext();
MyBean bean = (MyBeanRemote) ctx.lookup("java:global/<portable jndi name of your bean>");
注意:不使用arg構造函數InitialContext()
。 因為我認為您的Java類已部署在服務器中。 否則,如果您的類是獨立的Java類,則可能需要指定上下文工廠類,具體取決於供應商。
注意:您將需要Bean的遠程接口,如果你從不同的應用程序進行調用EJB( 即:不同的戰爭,耳朵......),或者本地接口就足夠了。
當無法創建初始上下文實現時,將引發此異常。 InitialContext類的文檔中描述了如何選擇初始上下文實現的策略。
在與InitialContext進行任何交互期間,不僅在構造InitialContext時,都可以引發此異常。 例如,初始上下文的實現可能僅在調用實際方法時才延遲檢索上下文。 應用程序不應依賴於何時確定初始上下文的存在。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.