使用 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/
并直接查找名称,例如 myString
和 myInteger
。它会更快,保证。
关于java - @Resource 可以用于在 EJB3.0 中注入(inject)原语吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6376730/