可以使用@Resource在EJB3.0中注入原语吗?

时间:2011-06-16 18:24:53

标签: java glassfish ejb-3.0 java-ee-6 ejb-3.1

使用Glassfish,我可以设置一个字符串jndi条目:

JNDI name: "com/xyzcompany/echo/EchoServiceBean/viewName"
Factory Class: org.glassfish.resources.custom.factory.PrimitivesAndStringFactory
Properties: value="Testing123"

然后我可以将这个容器配置的字符串注入我的EJB:

    @Resource(lookup = "com/xyzcompany/echo/EchoServiceBean/viewName")
    String viewName;

lookup =似乎在内部执行InitialContext.lookup(...)。但是,这使用了ejb3.1,但不幸的是我的prod环境只是ejb3.0。

我想我想弄清楚是否有办法使用@Resource(name =)或@Resource(mappedName =)做类似的事情? name =似乎是应用程序特定的,所以我应该能够以某种方式将相对名称映射到全局JNDI名称,但我无法弄清楚映射的注释。

谢谢!

1 个答案:

答案 0 :(得分:35)

所有8个原始包装器和String都支持@Resource类型,可通过在标准ejb-jar.xml文件中声明它们来查找或注入。

声明名称值(和类型)对

这是通过部署描述符中的<env-entry> xml元素完成的。

在EJB 3.0中,您必须为希望引用相同名称/值对的每个bean执行此操作。这是因为EJB最初的设计与Servlet不同,每个EJB实际上都有自己的私有JNDI名称空间java:comp/env,而同一模块中的所有Servlet共享相同的java:comp/env

<ejb-jar>
  <enterprise-beans>
    <session>
      <ejb-name>MySessionBean</ejb-name>
      <env-entry>
        <env-entry-name>myBoolean</env-entry-name>
        <env-entry-type>java.lang.Boolean</env-entry-type>
        <env-entry-value>true</env-entry-value>
      </env-entry>
      <env-entry>
        <env-entry-name>myString</env-entry-name>
        <env-entry-type>java.lang.String</env-entry-type>
        <env-entry-value>hello world</env-entry-value>
      </env-entry>
      <env-entry>
        <env-entry-name>myDouble</env-entry-name>
        <env-entry-type>java.lang.Double</env-entry-type>
        <env-entry-value>1.1</env-entry-value>
      </env-entry>
      <env-entry>
        <env-entry-name>myLong</env-entry-name>
        <env-entry-type>java.lang.Long</env-entry-type>
        <env-entry-value>12345678</env-entry-value>
      </env-entry>
      <env-entry>
        <env-entry-name>myFloat</env-entry-name>
        <env-entry-type>java.lang.Float</env-entry-type>
        <env-entry-value>1.3</env-entry-value>
      </env-entry>
      <env-entry>
        <env-entry-name>myInteger</env-entry-name>
        <env-entry-type>java.lang.Integer</env-entry-type>
        <env-entry-value>1024</env-entry-value>
      </env-entry>
      <env-entry>
        <env-entry-name>myShort</env-entry-name>
        <env-entry-type>java.lang.Short</env-entry-type>
        <env-entry-value>42</env-entry-value>
      </env-entry>
      <env-entry>
        <env-entry-name>myByte</env-entry-name>
        <env-entry-type>java.lang.Byte</env-entry-type>
        <env-entry-value>128</env-entry-value>
      </env-entry>
      <env-entry>
        <env-entry-name>myCharacter</env-entry-name>
        <env-entry-type>java.lang.Character</env-entry-type>
        <env-entry-value>D</env-entry-value>
      </env-entry>
    </session>
  </enterprise-beans>
</ejb-jar>

对于幸运地使用EJB 3.1的读者,您可以使用全局JNDI并在application.xml中声明它们,并通过java:app/myString从任何地方查找它们。大多数供应商多年来一直拥有的功能,现在最终成为Java EE 6的标准功能。也可以通过@Resource(lookup="java:app/myString")

注入这些条目

Java EE 6中的新功能还支持两种额外的env-entry-type类型,java.lang.Class和任何枚举。例如:

<env-entry>
  <env-entry-name>myPreferredListImpl</env-entry-name>
  <env-entry-type>java.lang.Class</env-entry-type>
  <env-entry-value>java.util.ArrayList</env-entry-value>
</env-entry>
<env-entry>
  <env-entry-name>myBillingStragety</env-entry-name>
  <env-entry-type>java.lang.Class</env-entry-type>
  <env-entry-value>org.superbiz.BiMonthly</env-entry-value>
</env-entry>
<env-entry>
  <env-entry-name>displayElapsedTimeAs</env-entry-name>
  <env-entry-type>java.util.concurrent.TimeUnit</env-entry-type>
  <env-entry-value>MINUTES</env-entry-value>
</env-entry>
<env-entry>
  <env-entry-name>myFavoriteColor</env-entry-name>
  <env-entry-type>org.superbiz.ColorEnum</env-entry-type>
  <env-entry-value>ORANGE</env-entry-value>
</env-entry>

使用Injection

引用它们

以上任何一项都可以通过@Resource注入。只是不要忘记填写name属性以匹配<env-entry-name>

@Stateless
public class MySessionBean implements MySessionLocal {

    @Resource(name="myString")
    private String striing;

    @Resource(name = "myDouble")
    private Double doouble;

    @Resource(name = "myLong")
    private Long loong;

    @Resource(name = "myName")
    private Float flooat;

    @Resource(name = "myInteger")
    private Integer inteeger;

    @Resource(name = "myShort")
    private Short shoort;

    @Resource(name = "myBoolean")
    private Boolean booolean;

    @Resource(name = "myByte")
    private Byte byyte;

    @Resource(name = "myCharacter")
    private Character chaaracter;

}

使用JNDI

引用它们

这些名称也可以通过EJB私有和可移植java:comp/env命名空间中的javax.naming.InitialContext进行标准查找。

@Stateless
public class MySessionBean implements MySessionLocal {

    @PostConstruct
    private void init() {

        try {
            final InitialContext initialContext = new InitialContext();// must use the no-arg constructor

            final String myString = (String) initialContext.lookup("java:comp/env/myString");
            final Boolean myBoolean = (Boolean) initialContext.lookup("java:comp/env/myBoolean");
            final Double myDouble = (Double) initialContext.lookup("java:comp/env/myDouble");
            final Long myLong = (Long) initialContext.lookup("java:comp/env/myLong");
            final Float myFloat = (Float) initialContext.lookup("java:comp/env/myFloat");
            final Integer myInteger = (Integer) initialContext.lookup("java:comp/env/myInteger");
            final Short myShort = (Short) initialContext.lookup("java:comp/env/myShort");
            final Byte myByte = (Byte) initialContext.lookup("java:comp/env/myByte");
            final Character myCharacter = (Character) initialContext.lookup("java:comp/env/myCharacter");
        } catch (NamingException e) {
            throw new EJBException(e);
        }
    }
}

使用SessionContext

引用它们

在EJB 3.0中,作为简化工作的一部分,我们添加了使用javax.ejb.SessionContext进行查找的功能。它基本上是相同的,但它上面有一点糖。

  • 不需要java:comp/env前缀
  • 不会抛出一个已检查的异常(而是会为缺少的名称抛出EJBException)

Service Locator模式在2003年引起了轰动,因此我们决定为EJB API构建一些方便。

@Stateless
public class MySessionBean implements MySessionLocal {

    @Resource
    private SessionContext sessionContext;

    @PostConstruct
    private void init() {

        final String myString = (String) sessionContext.lookup("myString");
        final Boolean myBoolean = (Boolean) sessionContext.lookup("myBoolean");
        final Double myDouble = (Double) sessionContext.lookup("myDouble");
        final Long myLong = (Long) sessionContext.lookup("myLong");
        final Float myFloat = (Float) sessionContext.lookup("myFloat");
        final Integer myInteger = (Integer) sessionContext.lookup("myInteger");
        final Short myShort = (Short) sessionContext.lookup("myShort");
        final Byte myByte = (Byte) sessionContext.lookup("myByte");
        final Character myCharacter = (Character) sessionContext.lookup("myCharacter");
    }
}

关于IntialContext恶意的附注

此外,随着我​​的供应商的开启,我可以告诉你,通过SessionContext查找可以避免一些缓慢的管道。

当你在InitialContext上执行'java:'查找时,调用会通过一堆箍来查找谁可以解析该名称,然后最终发送到必须查找状态的供应商从线程中找出谁问及他们应该得到什么名称空间。无论您传递给InitialContext的属性以及供应商在其构造中初始化的上下文,它都会在每次调用时执行此操作。 'java:'只是跳过了所有这些。作为供应商,这是一个相当令人沮丧的部分。这也是新javax.ejb.embedded.EJBContainer API在任何地方都不使用InitialContext的原因,只是引用javax.naming.Context这是一个实际的接口而不是具有强烈和钝的管道的具体“工厂”类。 / p>

如果供应商做得对,那么在SessionContext上进行调用应该会快得多。至少在OpenEJB中,包括ThreadLocal在内的所有内容都被跳过,调用直接进入该bean的JNDI命名空间,该命名空间已经附加到SessionContext

避免InitialContext开销的另一种方法是在@PostConstruct中简单地查找java:comp/env一次并保留生成的Context对象并仅使用它。然后,不要使用java:comp/env/为查找添加前缀,只需直接查找名称,例如myStringmyInteger。它会更快,更有保障。