在EJB 3.1或CDI中定义和注入映射

时间:2014-08-04 07:24:53

标签: spring ejb cdi ejb-3.1

在Spring开发几年之后,我转而使用EJB,我不满意这个用例没有解决方案。让我们说它是由地图实现的策略模式。在Spring中,它可能看起来像这样。

<bean id="myBean" class="MyBeanImpl">
    <property name="handlers">
        <map>
            <entry key="foo" value-ref="fooHandler"/>
            <entry key="bar" value-ref="barHandler"/>
    </property>
</bean>

在EJB / CDI中,我有这个。

@Stateless
public class MyBeanImpl implements MyBean {

    private Map<String, Class<? extends Handler>> handlers = new HashMap<>();

    @PostConstruct
    public void init() {
        handlers.put("foo", FooHandlerImpl.class);
        handlers.put("bar", BarHandlerImpl.class);
    }

    //jndi lookup handlerClass.getSimpleName()

}

请注意,jndi查找适用于实现,而不适用于接口。难道没有更好的解决方案吗?不,我不想拥有单独的字段(foo,bar),注入它们并在之后创建地图(它可以是巨大的列表并经常更改)。理想情况下,在任何配置更改的情况下,我根本不会触及MyBeanImpl类。

2 个答案:

答案 0 :(得分:1)

试试这个:

@Inject @Any
private Instance<Handler> handlers;

private Map<String, Handler> handlerMap = new HashMap<>();


@PostConstruct
private void init() {
    for (Handler handler : handlers) {
        handlerMap.put(handler.getName(), handler);
    }
}

假设您的Handler界面有某种getName()方法。

答案 1 :(得分:1)

更像CDI的方式如下:

@Qualifier
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
public @interface Handles {
    String value();
}


public class HandlerLiteral extends AnnotationLiteral<Handles> implements Handles{
    private final String value;
    public HandlerLiteral(String value) {
        this.value = value;
    }
    @Override
    public String value() {
        return value;
    }
}

然后,您可以使用Handler为每个@Handles("someName")实施注释,例如您在此处使用的类名称。这里使用限定符更符合CDI的工作方式,我们使用内部Instance对象来解析适当的bean。然后在您的服务代码(或任何地方),您只需:

@Inject @Any
private Instance<HandlerService> handlerInstance;

...
handlerInstance.select(new HandlerLiteral("whateverName")).get().handle(context);

如果你真的被限制使用地图,这对你不起作用。但这应该允许更动态的注册,并且基本上查看上下文中的每个处理程序。