【问题标题】:@EJB annotation does not work for initialize bean within the EJB application@EJB 注释不适用于在 EJB 应用程序中初始化 bean
【发布时间】:2013-05-02 18:36:06
【问题描述】:

我有一个具有这种结构的 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
我发现this link 和我有同样的问题,但那里的解决方案似乎对我不起作用。我做错什么了吗?

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 注解只能在由 servlet 容器管理的类中正常工作(例如:servlet、托管 bean、EJB 等)。除非最近发生了一些变化,否则我不希望它在随机的 pojo 类中工作。
  • 你看junitee.org了吗?
  • 这是an answer,这也表明@EJB 仅适用于托管类...

标签: java unit-testing junit ejb


【解决方案1】:
  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 文档不同;
    • 从文档看来,JNDI 查找名称需要是 "ejb:..." 而不是 "java:app/..." 因为 JBoss EJB-client-project 代码使用它来拦截查找.同样来自 Java EE 6 平台规范 EE.5.2.2:java:app 命名空间中的名称由单个 Java EE 应用程序中所有模块中的所有组件共享。如果您的测试是使用 java:app 的单独 JSE 应用程序,我怀疑 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 服务器上自行运行测试代码。它动态地将测试代码部署到配置的container(s) 并运行测试。它支持@EJB 注解,JNDI 连接变得简单,您可以在单元测试中包含 Java EE 类,而无需模拟或重构以从中抽象出来。

【讨论】:

  • 感谢您非常明确的回答!我不知道我应该使用ejb:&lt;app-ear-name&gt;/&lt;module-jar-name&gt;...。这解决了我的问题。谢谢!
【解决方案2】:

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 类,您可能需要指定上下文工厂类,具体取决于供应商。

注意:如果您从不同的应用程序(即:不同的战争, ear ...) 否则 本地 界面就足够了。

【讨论】:

  • 感谢您帮助我。我已经使用lookup 方法进行了测试,但没有成功。请在我最初的帖子中查看我的编辑。我的 Bean 有 Remote 接口。
  • @Rox,ejb bean 的映射 jndi 名称是什么?
  • “您的 java 类部署在我认为的服务器中” - 他正在运行 JUnit。我不认为他在服务器上运行。这就是为什么他拥有用于具有远程访问权限的 InitialContext 构造的详细的、特定于供应商的属性。
  • 是的,在他最初的 Q 中没有注意到 @Test。
【解决方案3】:

当无法创建初始上下文实现时会引发此异常。 InitialContext 类的文档中描述了如何选择初始上下文实现的策略。

在与 InitialContext 的任何交互过程中都可能引发此异常,而不仅仅是在构造 InitialContext 时。例如,初始上下文的实现可能仅在调用实际方法时才延迟检索上下文。应用程序不应依赖于何时确定初始上下文的存在。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-05
    • 1970-01-01
    • 2014-10-12
    • 1970-01-01
    相关资源
    最近更新 更多