在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类。
答案 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);
如果你真的被限制使用地图,这对你不起作用。但这应该允许更动态的注册,并且基本上查看上下文中的每个处理程序。