在@serverEndpoint class 中注入 EJB 导致 NullPointerException

Inject EJB in @serverEndpoint class results in NullPointerException

我正在使用 Swarm Wildfly 部署此应用程序。 基本上我正在制作一个支持 websocket 的应用程序。

我想注入一个单例,它将在修改变量结果的启动时启动。

访问“/rafflethis”后 link,用户将能够看到将通过会话发送的结果。

结果是roll变量null

这是class

@Singleton
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class runMe implements RaffleManager{
  private static final Logger LOGGER = Logger.getLogger(runMe.class.getName());

  private static String result;

  @PostConstruct
  public void onStartup() {
    System.out.println("Initialization success.");
  }

  @Schedule(second = "*/10", minute = "*", hour = "*", persistent = false)
  public void run() throws Exception{
    int i = 0;
    while (true) {
      Thread.sleep(1000L);
      result = UUID.randomUUID().toString().toUpperCase();
      i++;
      LOGGER.log(Level.INFO, "i : " + i);
    }
  }

  public String getResult() {
    return result;
  }
}

界面

public interface RaffleManager {
  String getResult();
}

还有“/rafflethis”

@ServerEndpoint("/rafflethis")
public class RaffleThis implements Serializable {
  @EJB
  RaffleManager roll;

  private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>());

  private static void sendMessageToAll(String message) {
    for (Session s : sessions) {
      try {
        s.getBasicRemote().sendText(message);
      } catch (IOException ex) {
        ex.printStackTrace();
      }
    }
  }

  @OnOpen
  public void monitorLuckyDip(Session session) throws Exception {
    sessions.add(session);
    while(true) {
      sendMessageToAll(roll.getResult());
    }
  }
}

我应该从哪里开始?谢谢!

查看源代码,我可能会认为是名称问题。 您的单例 bean "runMe" 是 bean 的实际名称而不是接口。

旁注:class 名称的最佳做法是将第一个字母大写。 RunMe 而不是 runMe。

@Singleton - 没有参数将自动命名您的 bean 以使用您的 class 名称中的 bean 约定进行查找。想象一下,如果你实现了多个接口,EJB 是如何取名的?所以使用 class 名称是合乎逻辑的。例如。如果您的 classname 是 TestMe,则 ejb 名称将是 testMe。

在你的情况下,因为你的 class 名称是 runMe,我认为 bean 名称将是 runMe。

为了保证查找不会失败,可以在@Singleton和@EJB中指定名称。

@Singleton(name = "runMe")
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class runMe implements RaffleManager{

然后在你的服务端点class

@ServerEndpoint("/rafflethis")
public class RaffleThis implements Serializable {
    @EJB(beanName ="runMe")
    RaffleManager roll;

该解决方案相当棘手,但确实非常简单。看看提供的图表。

这是代码

逻辑实现:

@Startup
@Singleton
public class RunMe{
  private static final Logger LOGGER = Logger.getLogger(RunMe.class.getName());


  @Inject
  MessageDTO messageDTO;


  @PostConstruct
  public void onStartup() {
    System.out.println("Initialization success.");
  }

  @Schedule(second = "*/10", minute = "*", hour = "*", persistent = false)
  public void run() throws Exception{
    //You can also substitute this method with constructor of the class -- removing the @Schedule annotation.
    int i = 0;
    while (true) {
      Thread.sleep(1000L);
      messageDTO.setText(UUID.randomUUID().toString().toUpperCase());
      i++;
      LOGGER.log(Level.INFO, "i : " + i);
    }
  }
}

MessageDTO:

@Singleton
public class MessageDTO {
  private static String text;

  public static String getText() {
    return text;
  }

  public static void setText(String text) {
    MessageDTO.text = text;
  }
}

Websocket 实现:

@ServerEndpoint("/rafflethis")
public class RaffleThis implements Serializable {

  private static final Logger LOGGER = Logger.getLogger(RaffleThis.class.getName());
  private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>());
  @Inject
  MessageDTO messageDTO;

  private static void sendMessageToAll(String message) {
    for (Session s : sessions) {
      try {
        s.getBasicRemote().sendText(message);
      } catch (IOException ex) {
        ex.printStackTrace();
      }
    }
  }

  @OnOpen
  public void monitorLuckyDip(Session session) throws Exception {
    sessions.add(session);
    while (true) {
      Thread.sleep(200);
      sendMessageToAll(messageDTO.getText());
    }
  }
}