使用@EJB作为Weld中的注入注释 [英] Use @EJB as injection annotation in Weld

查看:97
本文介绍了使用@EJB作为Weld中的注入注释的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序,它是JavaEE(服务器端)和JavaSE(客户端)的一部分。由于我希望该客户端具有良好的体系结构,因此我在其中使用了Weld来注入各种组件。其中一些组件应该是服务器端@EJB。

I have an application which is part JavaEE (the server side) part JavaSE (the client side). As I want that client to be well architectured, I use Weld in it to inject various components. Some of these components should be server-side @EJB.

我打算做的是扩展Weld体系结构,以提供允许Weld执行JNDI查找的组件当客户端尝试引用EJB实例时,请加载它们。但是我该怎么做呢?

What I plan to do is to extend Weld architecture to provide the "component" allowing Weld to perform JNDI lookup to load instances of EJBs when client tries to reference them. But how do I do that ?

在其他方面,我想在客户端使用

In other worrds, I want to have

/ p>

on the client side

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

在服务器端

@Stateless
public class MyEJB implements MyEJBInterface {
}

在创建ClientCode对象时,使用Weld隐式执行JNDI查找。我该怎么做?

With Weld "implicitely" performing the JNDI lookup when ClientCode objects are created. How can I do that ?

推荐答案

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

Basically, doing so requires write a so-called portable CDI extension.

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

But, as it is quite long and requires a few tweaks, let me explain it further.

就像焊接文档解释的那样,第一步是创建一个实现 扩展 标记接口,在其中将编写与有趣的CDI事件相对应的代码。在这种精确的情况下,在我看来,最有趣的事件是 AfterBeanDiscovery 。确实,此事件发生在CDI impl找到了所有本地 bean之后。

Like weld doc explains, first step is to create a class that implements the Extension tagging interface, in which one will write code corresponding to interesting CDI events. In that precise case, the most interesting event is, to my mind, AfterBeanDiscovery. Indeed, this event occurs after all "local" beans have been found by CDI impl.

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

So, writing extension is, more opr less, writing a handler for that event :

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反射对象转换为更高级的焊接对象(在我的情况下)

Creating the bean is not a trivial operation : it requires transforming "basic" Java reflection objects into more advanced weld ones (well, in my case)

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类。但是在此之前,需要在注释领域中进行少量旅行。

Finally, one has to write the JndiBean class. But before, a small travel in annotations realm is required.

首先,我使用 @EJB 一个。一个的想法:Weld使用限定符注释方法调用result来构建bean的哈希码!因此,我创建了自己的 @JndiClient 批注,该批注不包含任何方法,也不包含任何常量,以使其尽可能简单。

At first, I used the @EJB one. A bad idea : Weld uses qualifier annotation method calls result to build hashcode of bean ! So, I created my very own @JndiClient annotation, which holds no methods, neither constants, in order for it to be as simple as possible.

两个概念在这里合并。

Two notions merge here.


  • 一方面, Bean 接口(对我而言)似乎可以定义Bean是什么。

  • 另一方面, InjectionTarget 在一定程度上定义了该bean的生命周期。

  • On one side, the Bean interface seems (to me) to define what the bean is.
  • On the other side, the InjectionTarget defines, to a certain extend, the lifecycle of that very bean.

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

From the literature I was able to find, those two interfaces implementations often share at least some of their state. So I've decided to impelment them using a unique class : the JndiBean !

在该bean中,大多数

In that bean, most of the methods are left empty (or to a default value) excepted

  • Bean#getTypes, which must return the EJB remote interface and all extended @Remote interfaces (as methods from these interfaces can be called through this interface)
  • Bean#getQualifiers which returns a Set containing only one element : an AnnotationLiteral corresponding to @JndiClient interface.
  • Contextual#create (you forgot Bean extended Contextual, didn't you ?) which performs the lookup :

@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客户端代码中,我可以编写

Well, now, in my glassfish java client code, I can write things such as

private @Inject @JndiClient MyRemoteEJB instance;

它可以正常工作

现在,用户凭据尚未得到管理,但我想使用CDI的 C 是完全有可能的:上下文...哦,不!不是上下文:范围

Well, for now, user credentials are not managed, but I guess it could be totally possible using the C of CDI : Contexts ... oh no ! Not contexts : scopes !

这篇关于使用@EJB作为Weld中的注入注释的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆