簡體   English   中英

@EJB注釋不適用於EJB應用程序中的初始化bean

[英]@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)
  1. 容器資源注入(例如@EJB)需要一個已填充的JNDI目錄,並且只能在Java EE容器中執行的Java EE受管組件內工作。 對於單元測試是一個挑戰。 請參閱JSR318 Java EE 6平台規范,第EE.5節“資源,命名和注入”。

  2. 您現在正在嘗試JNDI查找-Java SE單元測試應用程序遠程連接其JNDI上下文。 缺點:必須部署完整的Java EE 6應用作為運行測試的前提; test-bugfix-build-deploy-retest生命周期可能會使事情變慢。

    一些問題:

    • 您的用戶名/密碼屬性不同於JBoss doc;
    • 從doc看來,JNDI查找名稱需要為"ejb:..."而不是"java:app/..."因為JBoss EJB客戶端項目代碼使用此名稱來攔截查找。 同樣來自Java EE 6平台規范EE.5.2.2: java:app命名空間中的名稱由單個Java EE應用程序中所有模塊中的所有組件共享。 如果您的測試是使用java:app的單獨的JSE應用java:app ,則我懷疑JBoss將其視為與單個Java EE應用程序分開的應用程序,並且查找將失敗。
    • 確保查找接口,而不是用於遠程訪問的實現類(即EJB無接口視圖)
    • 您引用的是一個不尋常的參考,該參考顯示了直接使用EJBClientConfiguration和EJBClientContext的情況。 似乎這不是必需/不推薦的。

    嘗試以下操作:

  3. 將來:使用CDI進行注射; JUnit + CDI @Mock用於“ POJO”單元測試; Arquillian,用於在容器中進行“ Java EE”單元/模塊測試。 然后,您可以避免/減少上述(2)的測試(JSE客戶端-> EJB)。 CDI支持:

    • 將Java EE資源注入POJO(包括@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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM