1

我想使用 Java EE 和 JBoss Application Server 实现绘画服务。

想象一个通过 URL 调用的方法

http://mypaint.com/apply?image=1&action=line&from=10,10&to=100,10

它对 id 为 1 的图像应用一个动作。该动作是“从点 (10,10) 到点 (100,10) 画一条线”。

“应用”方法如下所示:

@Inject
private ImageProcessorServer processors

@GET
@Path("/apply")
public Response apply(
    @QueryParam(value = "image") int imageId,
    @QueryParam(value = "action") String action,
    //some parameters more...
) {
     … //check if user is allowed to access the image
     ImageProcessor processor = processors.get(imageId); 
       //get image processor by image id
     processor.apply(action/*, from, to*/);
}

“ImageProcessorServer”看起来像这样:

@Singleton
@Startup
public class ImageProcessorServer {
   private Map<Integer, ImageProcessor> processors =
       new HashMap<Integer, ImageProcessor>();  
   @Lock(LockType.WRITE)
   public ImageProcessor get(int imageId) {
       ImageProcessor processor = processors.get(imageId);
       if(processor == null) {
           processor = new ImageProcessor(imageId);
           processors.put(imageId, processor);
       }
       return processor;
   }
}

确保每个图像只生成一个 ImageProcessor 是一个单例(在互斥下生成 → Write-Lock)。

现在的问题:如何在 ImageProcessor 类中注入我的数据访问对象(用于操作我的数据库)?DAO 是简单的无状态 bean。我的 ImageProcessor 应该是这样的:

public class ImageProcessor {
   @Inject
   private ActionDao actionDao;
   private Image image;

   public ImageProcessor(int imageId) { … }

   public void apply(String action, ...) {
      //change image
      //actionDao.persist(actionObject)
   }
}

但这不起作用。ActionDao 为 NULL。

我当前的解决方案是在使用 DAO 的每个方法中将 DAO 作为参数传递,如下所示:

public ImageProcessor(int imageId, ImageDao dao) { … }

public void apply(String action, …, ActionDao dao, ImageDao dao2, …) {
   //change image
   //dao.persist(actionObject)
}

具有相同图像 id 的请求共享相同的图像处理器很重要。一个客户端可以有多个具有不同图像 ID 的请求。

在此链接下 使用 POJO 中的依赖注入注入 EJB 据说可以使用工厂。但我不知道如何解决这个问题。有人可以为此提供代码吗?

有人知道解决我的问题的优雅方法吗?

4

3 回答 3

1

在您的情况下,您可以手动查找您的 bean。为此,您可以添加一个静态 util 方法来获取 bean 管理器:

 public static BeanManager getBeanManager()
 {
    try{
        InitialContext initialContext = new InitialContext();
        return (BeanManager) initialContext.lookup("java:comp/BeanManager");
    catch (NamingException e) {
        log.error("Couldn't get BeanManager through JNDI");
        return null;
    }
  }

然后您可以在单例 EJB 中手动查找您的 bean,然后所有注入都将发生在您的 bean 中:

 public ImageProcessor getFacade()
 {
    BeanManager bm = getBeanManager();
    Bean<ImageProcessor> bean = (Bean<ImageProcessor>) bm.getBeans(ImageProcessor.class).iterator().next();
    CreationalContext<ImageProcessor> ctx = bm.createCreationalContext(bean);
    ImageProcessor ip= (ImageProcessor) bm.getReference(bean, ImageProcessor.class, ctx); // this could be inlined, but intentionally left this way
    return ip;
 }

查找 bean 后,使用 setter 方法设置图像 id,然后将其放入地图中。

尝试制作一个用于手动查找 bean 的 util 类,然后您可以在整个项目中重用它。

Seam3、Myface CODI 和 DeltaSpike 也有一些实用程序来执行这些常规过程。

有关更多信息,请查看此示例

于 2012-08-30T03:06:50.927 回答
0

对于要注入的字段,bean 必须由 CDI 框架创建。

我可以找到几种“CDI”方式来创建,ImageProcessor但由于 imageId 的范围和处理器之间存在主席关系,它看起来不太好。(需要初始化的 FYI bean 应该通过@Producer带注释的方法创建)

解决该问题的最简单方法是将 DAO 注入单例中(因为它是无状态的,不应该成为问题)并通过构造函数将其提供给处理器(这将设置 DAO 字段)。这是我认为的清理方式,您将ImageProcessor创建仅限于单例)

于 2012-08-29T18:46:53.027 回答
0

我找不到使用生产者方法的方法,因为 EJB 是单例的,并且所有注入都将在 EJB 创建时发生一次。

首先添加限定符注释:@ImageProcessor

然后定义一个生产者方法:

@produces  @ImageProcessor
public ImageProcessor getImageProcessor(){
  long imageId = // Get your image id from request parameter map
  ImageProcessor processor = new ImageProcessor(imageId);
  return processor;
} 

然后使用如果您在单例中使用注入,它将为所有图像注入一次,因为您的 EJB 是单例!

@Inject @ImageProcessor
private ImageProcessor ip;     

因此,对于您的用例,这不是一个好方法,除非您再次在 EJB 中使用手动查找,但另一个问题是生产者方法中的线程问题!

于 2012-08-30T03:20:29.473 回答