9

我正在使用 PostgreSQL DB 并应用它的LISTEN/NOTIFY功能。所以我的侦听器在我的 AS(应用程序服务器)上,并且我在我的数据库上配置了触发器,这样当对表执行 CRUD 操作时,NOTIFY就会在 AS 上发送请求。

java中的监听器类:

        @Singleton
        @Startup
    NotificationListenerInterface.class)
        public class NotificationListener extends Thread implements NotificationListenerInterface {

            @Resource(mappedName="java:/RESOURCES") 
            private DataSource ds;

            @PersistenceContext(unitName = "one")
            EntityManager em;

            Logger logger = Logger.getLogger(NotificationListener.class);

            private Connection Conn;
            private PGConnection pgConnection = null;
            private NotifyRequest notifyRequest = null;

            @PostConstruct
            public void notificationListener() throws Throwable {

                System.out.println("Notification****************");
                try
                {


                    Class.forName("com.impossibl.postgres.jdbc.PGDriver");
                    String url = "jdbc:pgsql://192.xx.xx.126:5432/postgres";


                    Conn = DriverManager.getConnection(url,"postgres","password");
                    this.pgConnection = (PGConnection) Conn;

                    System.out.println("PG CONNECTON: "+ pgConnection);
                    Statement listenStatement = Conn.createStatement();
                    listenStatement.execute("LISTEN notify_channel");
                    listenStatement.close();

                    pgConnection.addNotificationListener(new PGNotificationListener() {

                        @Override
                        public void notification(int processId, String channelName, String payload){

                            System.out.println("*********INSIDE NOTIFICATION*************");

                            System.out.println("Payload: " + jsonPayload);

}

因此,当我的 AS 启动时,我已配置在启动时调用侦听器类 ( @Startup annotation) 并开始在频道上侦听。

现在,如果像测试我手动编辑数据库中的表,生成通知并且 LISTENER 接收它,那么这工作正常。

但是,当我以编程方式在表上发送 UPDATE 请求时,UPADTE 已成功执行,但 LISTENER 没有收到任何内容。

当我发送请求时,我感觉与 LISTENER 的连接断开了(它还与编辑实体建立了连接),但我不确定。我阅读了有关永久连接和池连接的信息,但无法决定如何进行。

我正在使用 pgjdbc ( http://impossibl.github.io/pgjdbc-ng/ ) jar 进行异步通知,因为 jdbc 连接需要轮询。

编辑:

当我使用标准 jdbc jar(而不是 pgjdbc)尝试使用上述侦听器进行轮询时,我会收到通知。

我这样做 PGNotification notif[] = con.getNotifications() 了,我收到了通知,但是像下面这样异步执行,我没有收到通知。

    pgConnection.addNotificationListener(new PGNotificationListener() {

         @Override
         public void notification(int processId, String channelName, String payload){

            System.out.println("*********INSIDE NOTIFICATION*************");
         }

解决了:

函数执行完成后,我的侦听器超出了范围,因为我的侦听器具有函数范围所以将它保存到我的启动 bean 类的成员变量中,然后它就可以工作了。

4

1 回答 1

7

通知侦听器由该库作为弱引用在内部维护,这意味着您必须在外部保存硬引用,这样它们就不会被垃圾收集。查看 BasicContext 类第 642 - 655 行:

public void addNotificationListener(String name, String channelNameFilter, NotificationListener listener) {

    name = nullToEmpty(name);
    channelNameFilter = channelNameFilter != null ? channelNameFilter : ".*";

    Pattern channelNameFilterPattern = Pattern.compile(channelNameFilter);

    NotificationKey key = new NotificationKey(name, channelNameFilterPattern);

    synchronized (notificationListeners) {
      notificationListeners.put(key, new WeakReference<NotificationListener>(listener));
    }

}

如果 GC 拾取您的侦听器,则对弱引用的“get”调用将返回 null 并且不会触发,如第 690 - 710 行所示

  @Override
  public synchronized void reportNotification(int processId, String channelName, String payload) {

    Iterator<Map.Entry<NotificationKey, WeakReference<NotificationListener>>> iter = notificationListeners.entrySet().iterator();
    while (iter.hasNext()) {

      Map.Entry<NotificationKey, WeakReference<NotificationListener>> entry = iter.next();

      NotificationListener listener = entry.getValue().get();
      if (listener == null) {

        iter.remove();
      }
      else if (entry.getKey().channelNameFilter.matcher(channelName).matches()) {

        listener.notification(processId, channelName, payload);
      }

    }

}

要解决此问题,请添加您的通知侦听器,如下所示:

/// Do not let this reference go out of scope!
    PGNotificationListener listener = new PGNotificationListener() {

    @Override
    public void notification(int processId, String channelName, String payload) {
        // interesting code
    };
};
    pgConnection.addNotificationListener(listener);

在我看来,弱引用是一个很奇怪的用例......

于 2016-06-24T01:38:28.893 回答