在共享POJO中使用依赖注入

时间:2012-08-29 17:08:13

标签: java-ee jboss dependency-injection cdi

我想使用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)绘制一条线”。

“apply”方法如下所示:

@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(在互斥下生成→写锁定),这是一个单例。

现在问题:如何在我的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的请求。

在此链接下 Using Dependency Injection in POJO's to inject EJB's 据说可以使用工厂。但我不知道如何解决这个问题。有人可以为此提供代码吗?

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

3 个答案:

答案 0 :(得分: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;
    }
  }

然后你可以在singleton 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也有一些实用程序来执行这些例行程序。

更多信息请查看this sample

答案 1 :(得分:0)

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

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

解决问题的最简单方法是将DAO注入单例(因为无状态不应该是一个问题)并通过construcor(将设置DAO字段)将其提供给处理器。这是我认为清洁方式,你将ImageProcessor创作仅限于单身人士)

答案 2 :(得分: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是Singleton!

@Inject @ImageProcessor
private ImageProcessor ip;     

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