在EJB 3.1或CDI中定义和注入地图 [英] Define and inject a map in EJB 3.1 or CDI

查看:174
本文介绍了在EJB 3.1或CDI中定义和注入地图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Spring开发了几年之后,我转而使用EJB,我不高兴,我没有解决这个用例的问题。让我们来看一下地图实现的策略模式。在Spring中,它可能看起来像这样。

 < bean id =myBeanclass = MyBeanImpl > 
< property name =handlers>
< map>
< entry key =foovalue-ref =fooHandler/>
< entry key =barvalue-ref =barHandler/>
< / property>
< / bean>

在EJB / CDI中,我有这个。



public class MyBeanImpl实现MyBean {

private Map< String,Class<?扩展处理程序>>处理程序=新的HashMap<>();

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

// jndi lookup handlerClass.getSimpleName()

}

注意jndi查找与实现而不是接口协同工作。是不是有更好的解决方案?而不,我不想有单独的字段(foo,bar),注入它们并创建地图(它可以是巨大的列表并经常更改)。理想情况下,在任何配置更改的情况下,我完全不会触摸MyBeanImpl类。

解决方案

CDI喜欢的方式如下:

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


public class HandlerLiteral extends AnnotationLiteral< Handles>手柄{
private final String value;
public HandlerLiteral(String value){
this.value = value;
}
@Override
public String value(){
返回值;
}
}

然后您将为每个处理程序实现与 @Handles(someName),例如你在这里使用的类名。在这里使用限定符更符合CDI的工作原理,我们使用内部的 Instance 对象来解析相应的bean。然后在您的服务代码(或任何地方)你会简单地做:

  @Inject @Any 
私有实例&HandlerService> ; handlerInstance;

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

如果您真的受限于使用地图,这对您无效。但这应该允许更多的动态注册,并且基本上查看你上下文中的每个处理程序。


After several years developing in Spring, I switched to EJB and I am not happy that I have no solution for this use-case. Let's say it is the strategy pattern implemented by a map. In Spring, it could look like this.

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

In EJB/CDI, I have this.

@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()

}

Mind that jndi lookup works with implementations, not interfaces. Isn't there any better solution? And no, I do not want to have separate fields (foo, bar), inject them and create the map afterwards (It can be huge list and changed often). Ideally, in case of any configuration change, I would not touch the MyBeanImpl class at all.

解决方案

The more CDI like way would look something like:

@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;
    }
}

You would then annotate each of your Handler implementations with @Handles("someName"), e.g. the class name as you're using it here. The use of a qualifier here is more in line with how CDI works, and we use the internal Instance object to resolve appropriate beans. Then in your service code (or wherever) you would simply do:

@Inject @Any
private Instance<HandlerService> handlerInstance;

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

If you're really constrained to using a map, this wouldn't work for you. But this should allow for more dynamic registration and essentially looks at every handler in your context.

这篇关于在EJB 3.1或CDI中定义和注入地图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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