在 Spring 中开发了几年之后,我转向了 EJB,但我很不高兴的是我没有针对这个用例的解决方案。假设这是通过 map 实现的策略模式。在 Spring 中,它可能看起来像这样。
<bean id="myBean" class="MyBeanImpl">
<property name="handlers">
<map>
<entry key="foo" value-ref="fooHandler"/>
<entry key="bar" value-ref="barHandler"/>
</map>
</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 查找适用于实现,而不是接口(interface)。难道就没有更好的解决办法吗?不,我不想有单独的字段(foo,bar),注入(inject)它们并随后创建 map (它可能是巨大的列表并且经常更改)。理想情况下,如果发生任何配置更改,我根本不会触及 MyBeanImpl 类。
最佳答案
更像 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;
}
}
然后,您可以使用 @Handles("someName")
注释每个 Handler
实现,例如您在此处使用的类名称。这里使用限定符更符合 CDI 的工作方式,并且我们使用内部 Instance 对象来解析适当的 bean。然后在您的服务代码(或任何地方)中您只需执行以下操作:
@Inject @Any
private Instance<HandlerService> handlerInstance;
...
handlerInstance.select(new HandlerLiteral("whateverName")).get().handle(context);
如果您确实只能使用 map ,那么这对您不起作用。但这应该允许更动态的注册,并且本质上会查看上下文中的每个处理程序。
关于spring - 在 EJB 3.1 或 CDI 中定义并注入(inject)映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25113624/