我想使用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 据说可以使用工厂。但我不知道如何解决这个问题。有人可以为此提供代码吗?
有人知道解决问题的优雅方法吗?
答案 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中的手动查找,否则这不是一个好方法,但另一个问题是生成器方法中的线程问题!