如何对托管对象使用策略模式

时间:2019-08-20 16:07:01

标签: cdi strategy-pattern

我处理队列中的消息。我使用传入消息中的数据来确定使用哪个类来处理消息。例如来源和类型。我将结合使用Origin和Type来查找FQCN,并使用反射实例化一个对象来处理消息。目前,这些处理对象都是实现公共接口的简单POJO。因此,我正在使用一种策略模式。

我遇到的问题是,我所有的外部资源(大多数是通过JPA访问的数据库)都已注入(@Inject),并且当我如上所述创建处理对象时,所有这些注入的对象都为空。我知道填充这些注入的资源的唯一方法是通过添加@stateless使接口的每个实现成为托管bean。仅仅这不能解决问题,因为仅在实现接口的类本身是注入的(即容器管理的)而不是由我创建的情况下填充注入的成员。

这是一个虚构的示例(敏感细节已更改)

public interface MessageProcessor
{
   public void processMessage(String xml);
}

@Stateless
public VisaCreateClient implements MessageProcessor
{
   @Inject private DAL db;
   …
}
public MasterCardCreateClient implements MessageProcessor…

在数据库中,有一个条目“ visa.createclient” =“ fqcn.VisaCreateClient”,因此,如果消息来源为“ Visa”,类型为“ Create Client”,则可以查找适当的处理类。如果我使用反射来创建VisaCreateClient,则db变量始终为null。即使我添加@Stateless并使用反射,db变量仍为null。只有当我注入VisaCreateClient时,才会填充db变量。像这样:

@Stateless
public QueueReader
{
   @Inject VisaCreateClient visaCreateClient;
   @Inject MasterCardCreateClient masterCardCreateClient;
   @Inject … many more times

   private Map<String, MessageProcessor> processors...

   private void init()
   {
      processors.put("visa.createclient", visaCreateClient);
      processors.put("mastercard.createclient", masterCardCreateClient);
      … many more times
   }
}

现在我有数十个消息处理器,如果我必须注入每个实现,然后将其注册在映射中,那么我将进行数十次注入。另外,如果我要添加更多处理器,则必须修改QueueReader类以添加新的注入并重新启动服务器。用我的旧代码,我只需要在数据库中添加一个条目,然后在类路径上部署新处理器-甚至不必重启服务器!

我想到了两种解决方法:

  1. 在使用反射创建消息处理器并传递所需资源后,立即向要调用的接口添加init(DAL db,OtherResource或...)方法。资源本身已注​​入QueueReader。
  2. 向processMessage(String xml,Context context)添加一个参数,其中Context只是注入到QueueReader中的资源的映射。

但是这种方法是否意味着我将为每个消息处理器使用相同的DAL对象实例?我相信这样做,而且只要不涉及任何状态,我相信就可以了-任何事务都将在DAL类之外启动。

所以我的问题是我的方法可行吗?这样做有什么风险?有没有更好的方法可以使用策略模式动态选择需要访问容器管理资源的实现?

感谢您的时间。

1 个答案:

答案 0 :(得分:0)

在类似的问题陈述中,我使用了处理器接口的扩展来决定它可以处理的数据对象类型。然后,您可以通过实例注入处理程序的所有变体,只需使用循环即可:

public interface MessageProcessor
{
   public boolean canHandle(String xml);
   public void processMessage(String xml);
}

在您的queueReader中:

@Inject
private Instance<MessageProcessor> allProcessors;

public void handleMessage(String xml) {
    MessageProcessor processor = StreamSupport.stream(allProcessors.spliterator(), false)
        .filter(proc -> proc.canHandle(xml))
        .findFirst()
        .orElseThrow(...);
    processor.processMessage(xml);
}

这在运行中的服务器上不起作用,但是只需实施并部署即可添加新处理器。