java - @Resource 可以用于在 EJB3.0 中注入(inject)原语吗?

标签 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"

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

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

lookup= 似乎在内部执行 InitialContext.lookup(...)。不过这个用的是ejb3.1,可惜我的prod环境只有ejb3.0。

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

谢谢!

最佳答案

所有 8 个原始包装器和字符串都支持 @Resource 类型,并且可以通过在标准 ejb-jar.xml 文件中声明它们来进行查找或注入(inject)。

声明名称值(和类型)对

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

在 EJB 3.0 中,您必须为每个希望引用相同名称/值对的 bean 执行此操作。这是因为 EJB 最初的设计不同于 Servlet,并且每个 EJB 从字面上都有自己的私有(private) JNDI namespace 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") 注入(inject)这些条目

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>

通过注入(inject)引用它们

以上任何一种都可以通过 @Resource 注入(inject)。只是不要忘记填写 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 私有(private)和可移植 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)

服务定位器模式在 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:”查找时,调用将转到 VM,通过一系列循环查找可以解析该名称的人,然后最终转到必须从线程查找状态的供应商弄清楚是谁问的以及他们应该获得什么命名空间。无论您将什么属性传递给 InitialContext 以及供应商在其构造中初始化了什么上下文,它都会在每次调用时执行此操作。 'java:' 简单地跳过所有这些。作为供应商,这是一个相当令人沮丧的部分。这也是为什么新的 javax.ejb.embedded.EJBContainer API 根本不在任何地方使用 InitialContext,而只是引用 javax.naming.Context,它是一个实际的接口(interface),而不是具有密集和钝管道的具体“工厂”类。

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

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

关于java - @Resource 可以用于在 EJB3.0 中注入(inject)原语吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6376730/

相关文章:

java - 使用 JDBC 连接将记录插入到 Apache Ignite Cluster 时出现异常

java - 将数据/对象附加到选项卡式布局中的选项卡

java - 如何使用 Java 代码检查客户端浏览器中是否启用了 JavaScript

java - Web 应用程序中的共享 session

java - 是否可以在同一事务中捕获运行时异常并引发应用程序异常? (ejb)

jakarta-ee - 为什么更喜欢 JNDI 查找而不是有状态 session bean 的 EJB 注入(inject)?

Java - 从单独的类打开一个新 View

java - 我们可以将安全领域添加到 glassfish-resources

java - Oracle glassfish4.1 jms数据库存储

java - JBoss 5.1.0 GA 中的@EJB?