在具有 RPC 调度的 GWTP 项目中使用 EJB

Using EJBs in a GWTP project with RPC Dispatch

我们在 web/enterprise 应用程序中使用 GWTP RPC Dispatch 和 Guice。我们希望使用 EJB 将我们的业务逻辑放在我们的 EAR 的单独模块中。由于 RPC Dispatch 在这里起作用,所以只有一个 servlet,它有点被封装了。所以没有直接的方法来注入我们的 EJB,至少在不失去 EJB 的容器管理的情况下是这样。

是否有其他方法可以将 EJB 集成到我们的应用程序中?或者我在这里遗漏了什么?

所以经过一些研究,我似乎有两种方法可以在 Guice/RPC Dispatch 应用程序中使用 EJB 注入:

1。集中注入

EJB 注入在 GuiceServletContextListener 或您的 child class 的任何名称中工作。在那里你可以通过 @EJB 注释注入一个 bean,然后将引用传递给 getInjector() 方法中的模块:

import javax.ejb.EJB;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.GuiceServletContextListener;

public class GuiceServletConfig extends GuiceServletContextListener {

    @EJB
    private SampleBeanLocal sampleBean;

    @Override
    protected Injector getInjector() {
        return Guice.createInjector(new ServerModule(), new BeanModule(sampleBean));
    }

}

2。自定义注释

另一种方法是创建一个自定义注释,然后使用它在不可能的地方注入 bean。 here.

描述了实现

由于代码示例中存在一些缺陷,我也将post我的解决方案放在这里:

注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ TYPE, METHOD, FIELD})
public @interface GuiceEJB {
    /**
     * Name of the bean.
     * 
     * @return Name of the bean.
     */
    String name();

    /**
     * Local EJB as default type.
     * 
     * @return bean type.
     */
    String type() default "local";
}

TypeListener

import java.lang.reflect.Field;

import com.google.inject.TypeLiteral;
import com.google.inject.spi.TypeEncounter;
import com.google.inject.spi.TypeListener;

/**
 * Custom Guice {@link TypeListener} for the {@link GuiceEJB} annotation.
 */
public class GuiceEJBTypeListener implements TypeListener {

    @Override
    public <I> void hear(TypeLiteral<I> typeLiteral, TypeEncounter<I> encounter) {
        Class< ? > clazz = typeLiteral.getRawType();
        while (clazz != null) {
            // iterate through the fields of the class
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(GuiceEJB.class)) {
                    encounter.register(new GuiceEJBMemberInjector<I>(field));
                }
            }
            // repeat for super class
            clazz = clazz.getSuperclass();
        }
    }
}

MembersInjector

import java.lang.reflect.Field;

import javax.naming.Context;
import javax.naming.InitialContext;

import com.google.inject.MembersInjector;

/**
 * Custom member injector for {@link GuiceEJB} annotations.
 */
public class GuiceEJBMemberInjector<T> implements MembersInjector<T> {

    /**
     * Field that needs injection.
     */
    private Field field;
    /**
     * Bean type.
     */
    private String type;
    /**
     * Bean name.
     */
    private String name;

    /**
     * @param field
     */
    public GuiceEJBMemberInjector(Field field) {
        this.field = field;
        GuiceEJB annotation = field.getAnnotation(GuiceEJB.class);
        this.type = annotation.type();
        this.name = annotation.name();
        this.field.setAccessible(true);
    }

    @Override
    public void injectMembers(T t) {
        try {
            if ("local".compareToIgnoreCase(this.type) == 0) {
                this.field.set(t, findLocalEJB());
            }
        } catch (Exception e) {
            throw new GuiceEJBInjectException(e);
        }
    }

    /**
     * Lookup an local EJB for the given field.
     * 
     * @return
     */
    private Object findLocalEJB() {
        Context initialContext = null;
        Object localRef = null;

        try {
            // look up the bean by name
            localRef = InitialContext.doLookup(this.name);
        } catch (Exception e) {
            throw new GuiceEJBInjectException(e);
        } finally {
            try {
                if (initialContext != null)
                    initialContext.close();
            } catch (Exception e) {
            }
        }

        return localRef;
    }

}