基本上,这样做需要写一个所谓的portable CDI extension。
但是,由于它很长并且需要一些调整,让我进一步解释一下。
便携式扩展
就像weld doc 解释的那样,第一步是创建一个实现Extension 标记接口的类,在其中编写与感兴趣的CDI 事件对应的代码。在这种情况下,在我看来,最有趣的事件是AfterBeanDiscovery。事实上,这个事件是在 CDI impl 找到所有“本地”bean 之后发生的。
因此,编写扩展程序是,更多操作更少,为该事件编写处理程序:
public void loadJndiBeansFromServer(
@Observes AfterBeanDiscovery beanDiscovery, BeanManager beanManager)
throws NamingException, ClassNotFoundException, IOException {
// Due to my inability to navigate in server JNDI naming (a weird issue in Glassfish naming)
// This props maps interface class to JNDI name for its server-side
Properties interfacesToNames = extractInterfacesToNames();
// JNDI properties
Properties jndiProperties = new Properties();
Context context = new InitialContext();
for (Entry<?, ?> entry : interfacesToNames.entrySet()) {
String interfaceName = entry.getKey().toString();
Class<?> interfaceClass = Class.forName(interfaceName);
String jndiName = entry.getValue().toString();
Bean<?> jndiBean = createJndIBeanFor(beanManager, interfaceClass, jndiName, jndiProperties);
beanDiscovery.addBean(jndiBean);
}
}
创建 bean 不是一个简单的操作:它需要将“基本”Java 反射对象转换为更高级的焊接对象(在我的例子中)
private <Type> Bean<Type> createJndIBeanFor(BeanManager beanManager, Class<Type> interfaceClass,
String jndiName, Properties p) {
AnnotatedType<Type> annotatedType = beanManager
.createAnnotatedType(interfaceClass);
// Creating injection target in a classical way will fail, as interfaceClass is the interface of an EJB
JndiBean<Type> beanToAdd = new JndiBean<Type>(interfaceClass, jndiName, p);
return beanToAdd;
}
最后,必须编写 JndiBean 类。但在此之前,需要在注释领域进行一次小旅行。
定义使用的注解
一开始,我用的是@EJB。 bad 想法:Weld 使用限定符注释方法调用结果来构建 bean 的哈希码!因此,我创建了自己的 @JndiClient 注释,它不包含任何方法,也不包含常量,以使其尽可能简单。
构造一个 JNDI 客户端 bean
两个概念在这里合并。
从我能够找到的文献中,这两个接口实现通常至少共享它们的一些状态。所以我决定使用一个独特的类来推动他们:JndiBean!
在那个 bean 中,除了大多数方法之外,大多数方法都是空的(或默认值)
-
Bean#getTypes,它必须返回 EJB 远程接口和所有扩展的@Remote 接口(因为这些接口的方法可以通过这个接口调用)
-
Bean#getQualifiers 返回一个只包含一个元素的 Set :一个 AnnotationLiteral 对应于 @JndiClient 接口。
-
Contextual#create(你忘记了 Bean 扩展的上下文,不是吗?)执行查找:
@Override
public T create(CreationalContext<T> arg0) {
// Some classloading confusion occurs here in my case, but I guess they're of no interest to you
try {
Hashtable contextProps = new Hashtable();
contextProps.putAll(jndiProperties);
Context context = new InitialContext(contextProps);
Object serverSide = context.lookup(jndiName);
return interfaceClass.cast(serverSide);
} catch (NamingException e) {
// An unchecked exception to go through weld and break the world appart
throw new LookupFailed(e);
}
}
仅此而已
用途?
好吧,现在,在我的 glassfish java 客户端代码中,我可以编写诸如
之类的东西
private @Inject @JndiClient MyRemoteEJB instance;
它可以正常工作
未来?
好吧,目前,用户凭据不受管理,但我想使用 CDI 的 C 完全有可能:上下文...哦不!不是上下文:scopes!