我有一个应用程序,该应用程序是Javaee(服务器端)部分Javase(客户端)。由于我希望该客户端进行良好的架构,因此我在其中使用焊接来注入各种组件。其中一些组件应为服务器端@EJB。

我计划要做的是扩展焊接体系结构,以提供“组件”,允许焊缝在客户端尝试参考时执行JNDI查找以加载EJB的实例。但是我该怎么做?

在其他忧虑中,我想拥有

在客户端

public class ClientCode {
    public @Inject @EJB MyEJBInterface;
}

在服务器端

@Stateless
public class MyEJB implements MyEJBInterface {
}

当创建客户端代码对象时,使用焊缝“隐含”执行JNDI查找。我怎样才能做到这一点 ?

有帮助吗?

解决方案

基本上,这样做需要写一个所谓的 便携式CDI扩展.

但是,由于它很长,需要进行一些调整,因此让我进一步解释。

便携式扩展

像Weld Doc所说的那样,第一步是创建一个实现该类别的类 Extension 标记接口,其中将编写与有趣的CDI事件相对应的代码。在这种确切的情况下,最有趣的事件是,在我看来 Afterbeandiscovery. 。实际上,在CDI IMPHEN发现所有“局部”豆之后,发生了此事件。

因此,写入扩展名更少,为该事件编写处理程序:

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 一。一个 坏的 想法:WELD使用预选程序注释方法调用结果来构建BEAN的哈希码!所以,我创造了自己的 @JndiClient 没有任何方法的注释都不是常数,以使其尽可能简单。

构建JNDI客户端

两个概念在这里合并。

  • 一方面 Bean 界面似乎(对我来说)定义了豆是什么。
  • 在另一侧, InjectionTarget 在一定的延伸中定义了那个非常豆的生命周期。

从我能够找到的文献中,这两个接口实现通常至少共享某些状态。因此,我决定使用独特的类推动他们: JndiBean !

在该豆中,大多数方法都空为空(或默认值)

  • Bean#getTypes, ,必须返回EJB远程接口和所有扩展 @Remote 接口(可以通过此接口来调用这些接口的方法)
  • Bean#getQualifiers 返回仅包含一个元素的集合:一个 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;

而且它没有任何问题

未来?

好吧,目前尚未管理用户凭据,但是我想使用 C CDI:上下文...哦,不!不是上下文: 范围 !

其他提示

CDI规格的第3.5节应提供帮助。您可能还需要使用EJB注释上的一些属性。另外,(可能不需要告诉您)确保在客户端上正确设置JNDI以引用服务器,并将任何所需的接口打包到客户端JAR中。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top