将@Singleton注入@ApplicationScoped导致NullPointerException

时间:2016-02-19 06:35:02

标签: java-ee dependency-injection glassfish ejb cdi

我正在使用EJB和WAR模块在glassfish中运行。 EJB模块包含一个管理与远程计算机的连接的单例,并且在特定事件的情况下,使用JMS发送消息。 WAR模块包含一个websocket服务器,它拦截JMS消息并将它们发送到连接的浏览器。它完美地运作。 现在我介绍一种“启动”方法:当一个新的客户端连接时,我想发送它的机器列表,所以javascript可以准备正确的div数。为此,我在单例bean中创建了一个返回列表的方法,我希望在新会话打开时调用它。

这是EJB模块中的单例:

@Singleton
public class TServer implements ServerListener, TServerLocal {
  private HashMap<String, Servers> servers = new HashMap<>();

  @EJB
  private JMSQueueProducer jms;

  @Override
  public void connect(String hostname, String username, String password) {
    Server server = new Server(hostname, username, password);
    server.addListener(this);
  }

  private void onServerEvent(String host, String data) {
    this.jms.textMessage(host + " " + data);
  }

  [...]
}

@Local
public interface TServerLocal {

  public void connect(String hostname, String username, String password);
  public void disconnect(String hostname);
  public LinkedList<String> list();

}

JMSQueueProducer是一个无状态EJB,仅用于将消息发送到JMS队列:

@Stateless
@LocalBean
public class JMSAsteriskQueueProducer {

  @Inject
  private JMSContext jmsContext;
  @Resource(mappedName = "jms/serverQueue")
  private Queue sQueue;

  public void textMessage(String message) {
    jmsContext.createProducer().send(sQueue, message);
  }
}

这是WAR模块中的websocket服务器:

@ApplicationScoped
@ServerEndpoint("/websocket")
public class WebSocketServer {

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

  @EJB
  private TServerLocal tServer;

  @OnOpen
  public void open(Session session) {
    sessions.add(session);
    LinkedList<String> servers = tServer.list();
  }

  [...]
}

如果我尝试启动会话,我会在tServer.list()处获得NullPointerException,这意味着tServer为null。 我尝试用@Inject更改@EJB,结果相同。我认为在CDI中调用EJB是完全合法的,我做错了什么?

1 个答案:

答案 0 :(得分:0)

你的@Singleton需要@LocalBean注释,因为除了无界面视图之外它还暴露了其他界面:

@LocalBean
@Singleton
public class TServer implements ServerListener, TServerLocal {
    ...
}