【问题标题】:Singleton CDI @Inject null pointer exception单例 CDI @Inject 空指针异常
【发布时间】:2017-08-28 01:19:07
【问题描述】:

我需要使用依赖注入从一些 ejb(无状态和单例)中触发事件。我不使用 Spring、Guice 等。 问题是当通过 getInstance() 调用它的方法时,我在其中一个 bean 中得到了 NPE。这是代码sn-p:

@Stateless
@LocalBean
public class ControllerStartStop {
    @Inject
    private Event<SomeWebMessage> webEvent; 

    public String startCircle(String passwordP, String passwordH) {
    .........
    String res = "some msg";
    webEvent.fire(new SomeWebMessage(res, 0));   // this works fine
    MainDay.getInstance().startDay();      // NullPointerException

这是 MainDay 单例:

@Singleton
public class MainDay {
    private static final MainDay mDay = new MainDay();
    public static MainDay getInstance() {   return mDay ;   }

    @Inject
    private Event<SomeWebMessage> webEvent; 

    public void startDay() {
        String s = new String("MainDay");
        webEvent.fire(new SomeWebMessage(s,0));   // NullPointerException

beans.xml 在 META-INF 中:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
                           http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       version="1.1" bean-discovery-mode="all">

</beans>

当我通过调用像 MainDay.initDS() 这样的静态方法或方法 startDay() 被 Sheduler (@Schedule(hour = "",分钟 = "",秒 = "/10")*。 不知道是什么原因

【问题讨论】:

    标签: java nullpointerexception singleton cdi inject


    【解决方案1】:

    请注意,@Singleton 表示容器(EJB 或 CDI,取决于它是哪个注解)将管理实例,即不应自己创建它。

    如果您通过private static final MainDay mDay = new MainDay(); 创建实例,则容器不会进行任何注入,因此webEvent 将为空。除此之外,容器不会知道该实例,并且在其他地方使用@Inject MainDay 很可能会产生另一个实例。

    因此只需直接使用注入(或查找,如果需要):

    class ControllerStartStop  {
      @Inject
      private MainDay mDay;
    
      ...
      public String startCircle(String passwordP, String passwordH) {
        ...
        String res = "some msg";
        webEvent.fire(new SomeWebMessage(res, 0)); 
        mDay.startDay();    
        ...
      }
    

    当我通过调用像 MainDay.initDS() 这样的静态方法或方法 startDay() 由 Sheduler (@Schedule(hour = "", minute = "", second = "/10")*. 我不知道是什么原因

    在不知道您的代码的情况下,这只是一个猜测,但我假设您在此处注入 MainDay 或使用 CDI/JNDI 查找。因此,如果没有实例,容器将创建一个实例并注入 Event 对象。

    【讨论】:

      【解决方案2】:

      NPE 1:

      目标 EJB MainDay 不应该“观察”该事件并调用其startDay() 方法吗?

      public void onEvent(@Observes SomeWebMessage event) {
          // if (...)
              startDay();
      }
      

      因此不需要静态的getInstance() 方法。

      NPE 2:

      @Inject Event<SomeWebMessage> webEvent; 
      

      依赖注入 (DI) 仅在您手动调用构造函数 new MainDay() 而是注入所需 bean 的实例并让 DI 容器处理构造时才有效。

      但是使用@Observes (javax.enterprise.event.Observes) 你应该能够删除所有臭的static 东西。

      【讨论】:

      • 还有一个单例观察在 ControllerStartStop、MainDay 以及可能一两个其他事件中触发的事件:@Singleton public class LongPollingNotifier { private final Queue&lt;AsyncContext&gt; peers = new ConcurrentLinkedQueue&lt;AsyncContext&gt;(); @Asynchronous public void notifyPeers(@Observes SomeWebMessage swm) ... 这种方法好吗?
      • 是的,你可以有多个独立的观察者。
      猜你喜欢
      • 1970-01-01
      • 2016-10-29
      • 2012-11-27
      • 2015-06-22
      • 1970-01-01
      • 2015-07-12
      相关资源
      最近更新 更多