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

Jon*_*her 10 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名称,但我无法弄清楚映射的注释.

谢谢!

Dav*_*ins 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>
Run Code Online (Sandbox Code Playgroud)

对于有幸使用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>
Run Code Online (Sandbox Code Playgroud)

使用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;

}
Run Code Online (Sandbox Code Playgroud)

使用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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用SessionContext引用它们

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

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

服务定位器模式在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");
    }
}
Run Code Online (Sandbox Code Playgroud)

关于IntialContext邪恶的旁注

此外,随着我​​的供应商帽子,我可以告诉你,有一些相当缓慢的管道,可以通过SessionContext查找在引擎盖下避免.

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

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

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

  • 我发现这个答案非常有用,尤其是关于`InitialContext`邪恶的部分.事实上,'java:'直接跳回来,即使你将它与一个实际指向远程JNDI树的InitialContext一起使用也很难理解并且难以解释. (4认同)