使用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名称,但我无法弄清楚映射的注释。
谢谢!
答案 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>
以上任何一项都可以通过@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;
}
这些名称也可以通过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);
}
}
}
在EJB 3.0中,作为简化工作的一部分,我们添加了使用javax.ejb.SessionContext
进行查找的功能。它基本上是相同的,但它上面有一点糖。
java:comp/env
前缀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");
}
}
此外,随着我的供应商的开启,我可以告诉你,通过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/
为查找添加前缀,只需直接查找名称,例如myString
和myInteger
。它会更快,更有保障。