【问题标题】:What are the types of classes/instances I can inject a CDI event into?我可以将 CDI 事件注入到哪些类型的类/实例中?
【发布时间】:2017-06-21 18:56:16
【问题描述】:

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

注意:我在带有 CDI 的 Tomcat 上,还安装了 JPA(在这个项目中切换到完整的 EE 服务器不是一个选项)

我不确定它是否应该是单例/应用程序范围内的单例,或者应该是每个请求(甚至是会话)。所以我的问题是:

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

  2. 哪一个最适合这个用例?

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

示例代码:

//Is this correct?
@WebListener
public class EventHandler
{
    @Inject
    @MyEventQualifier
    private Event<MyEvent> myEvent;

    public void fireEvent(MyEvent anEvent)
    {
        myEvent.fireAsync( anEvent );
    }
}

【问题讨论】:

    标签: java tomcat servlets jakarta-ee cdi


    【解决方案1】:

    基本容器类是您的标准“托管”对象,例如您列出的对象(WebListeners、Filters、Servlet)。这些充当上下文链的根。由于这些是由 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&lt;Pojo&gt; 注入到servlet 中,然后在其上使用Instance.get,而不仅仅是直接使用Pojo。这样做的原因是 Servlet 在 Web 应用程序中名义上是单例,所以如果你注入了一个实际的 Pojo,你的所有请求都将使用完全相同的 Pojo 实例(不太可能是你想要的)。

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

    如果您愿意对遗留代码进行更改,您可以做自己喜欢的事情,并且没有真正需要跳过箍来弥合 CDI 遗留的鸿沟。只需根据需要将它们转入 CDI。

    【讨论】:

    • 对于最后一个,我将如何注入 POJO?如果没有,我也可以将事件注入到 POJO 中吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    相关资源
    最近更新 更多