我可以将CDI事件注入哪些类/实例类型?

时间:2017-06-21 18:56:16

标签: java tomcat servlets java-ee cdi

我希望有一个可以触发事件的类。理想情况下,我希望将它放在POJO中(处理POJO中的遗留代码),但我知道这是不可能的。所以相反,我希望POJO可以调用哪些内容来激活事件。

注意:我在使用CDI的Tomcat上,JPA也安装了(在此项目中不能切换到完整的EE服务器)

我不确定它应该是单身/应用程序范围的单身人士,还是应该按照请求(甚至是会话)。所以我的问题是:

  1. 什么可以注入事件? (例如@WebListener@SingletonRequestScoped@Stateless

  2. 哪一个对这个用例最有意义?

  3. POJO如何访问该类/实例(从servlet调用POJO)?

  4. 示例代码:

    //Is this correct?
    @WebListener
    public class EventHandler
    {
        @Inject
        @MyEventQualifier
        private Event<MyEvent> myEvent;
    
        public void fireEvent(MyEvent anEvent)
        {
            myEvent.fireAsync( anEvent );
        }
    }
    

1 个答案:

答案 0 :(得分:1)

基本容器类是您标准的“托管”对象,就像您列出的那样(WebListeners,Filters,Servlets)。这些作为上下文链的根源。由于这些都是由CDI管理的,因此它们注入的任何内容也都会被管理,并且在那条线上。

如果您的Servlet(例如)注入PojoX,PojoX可以注入PojoY,然后打开和关闭。游戏是为了避免使用new而是使用CDI构造来创建您的POJO。

至于克服传统的POJO / CDI鸿沟,你可以做一些事情。

您可以将一个EventHandler实例注入Servlet,然后将该实例作为参数传递给POJO。

您可以将该实例作为属性粘贴到请求中,或者在首次创建Servlet时将实例推送到ServletContext中。

您可以将EventHandler设为@Singleton,并在其@PostConstruct设置一个静态变量,该变量可通过标准的静态getInstance调用返回。

您可以让POJO直接调用容器进行查找(或调用实用程序函数)。

当然,如果POJO可以自己注入,那就这样做吧。

评论的补遗:

如果适合您工作,您可以简单地注入POJO。

以下是一个例子:

@WebServlet(name = "NewServlet", urlPatterns = {"/NewServlet"})
public class NewServlet extends HttpServlet {

    @Inject
    Instance<Pojo> pojoInstance;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        Pojo pojo = pojoInstance.get();
        String world = pojo.getWorld();

        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
            /* TODO output your page here. You may use following sample code. */
            out.println("<!DOCTYPE html>");
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet NewServlet</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h1>Servlet NewServlet at " + request.getContextPath() + "</h1>");
            out.println("<p>Hello " + world);
            out.println("</body>");
            out.println("</html>");
        }
    }
}

public class Pojo {

    @Inject
    Event<PojoEvent> pojoEventHdlr;

    @PostConstruct
    public void postConstruct() {
        System.out.println("Look, another Pojo!");
    }

    public String getWorld() {
        PojoEvent pe = new PojoEvent("World event pojo fired");
        pojoEventHdlr.fire(pe);

        return "world";
    }
}

public class PojoEvent {

    String msg;

    public PojoEvent() {
    }

    public PojoEvent(String msg) {
        this.msg = msg;
    }

    public String toString() {
        return "PojoEvent with msg: " + msg;
    }
}

@Singleton
public class SingletonPojo {

    public void pojoEventObserver(@Observes PojoEvent pe) {
        System.out.println("We got a PojoEvent " + pe);
    }
}

需要注意的重要一点是,我将一个Instance<Pojo>注入到servlet中,然后在其上使用Instance.get,而不是直接使用Pojo。原因是Servlet在Web应用程序中名义上是Singletons,所以如果你注入一个真正的Pojo,你的所有请求都将使用完全相同的Pojo实例(不太可能你想要的)。

你可以看到Pojo触发事件,我有一个@Singleton类来观察事件并转出消息。

如果您愿意对遗留代码进行更改,您可以按自己喜欢的方式进行更改,并且没有必要跳过桥接来连接CDI&lt; - &gt;遗产鸿沟。只需将它们滚入CDI即可。