【问题标题】:Mediation between Hibernate Entity Listeners and netty-socketioHibernate Entity Listeners 和 netty-socketio 之间的中介
【发布时间】:2016-08-01 21:44:46
【问题描述】:

我正在开发一个小型 Java 项目,这是我想要实现的基本理念:我在 netty-socketio 上有一个层,它接受来自浏览器的 socket.io 请求,我使用 JPA 2.1/休眠以将请求的更改持久保存到数据库。不同之处在于我也有流请求的概念,因为用户将请求集合的当前状态和所有未来的更新。为了从数据库中获取实时更新,我使用了实体监听器。我正在寻找一种将实体侦听器方法连接到 socketio 连接之上的处理程序的可靠方法,即当它感兴趣的数据发生更改时应该通知流处理程序,以便它可以将更新发送到管道中。我试图想出一个单一的主持人,实体侦听器可以发布更新,订阅的处理程序可以使用它,所有这些都基于String topic,很像发布订阅。我遇到的问题是:让我们以 POJO User 为例。当插入一个新的user 时,UserEntityListener#PostInsert 启动,它通过.publish 调用将user 转发给NotifierNotifier 使用<?> 作为数据类型,它通过类似Callable 的接口调用相关方:

public interface Notifiable {
    public <T> void onEvent(T data);
}

所以现在在适当的处理程序中调用它的实现,但它具有泛型类型,我必须手动转换它(处理程序知道它应该接收的类型)。我的问题是,我可以在没有明确演员表的情况下做到这一点吗?有没有一个好的框架可以让所有这些低级的修补变得无用?我想要一个集中的解决方案来弥补差距,否则所有的样板都会杀死我。

EDIT 添加了相关来源。

通知类:

class Subscriber {
    public String topic;
    public Notifiable notifiable;
    public Subscriber(String topic, Notifiable n) {
        this.topic = topic;
        this.notifiable = n;
    }
}

public class Notifier {
    private static Notifier instance = null;
    private List<Subscriber> subscribers = new ArrayList<Subscriber>();

    public Notifier() {};
    public void subscribe(String topic, Notifiable n) {
        if (!this.hasSubscriber(topic, n)) {
            this.subscribers.add(new Subscriber(topic, n));
        }
    }
    public <T> void publish(String topic, T data) {
        for (Subscriber s : this.subscribers) {
            if (s.topic.equals(topic)) {
                s.notifiable.onEvent(data);
            }
        }
    }
    public Boolean hasSubscriber (String topic, Notifiable n) {
        for (Subscriber s : this.subscribers) {
            if (s.topic.equals(topic) && s.notifiable == n) {
                return true;
            }
        }
        return false;
    }

    public static Notifier getInstance() {
        if (instance == null) {
            instance = new Notifier();
        }
        return instance;
    }
}

实体监听器:

@PostPersist
public void PostInsert(User u) {
    Notifier.getInstance().publish("user/new", u);
}

Socketio 处理程序:

Notifier.getInstance().subscribe("user/new", (new Notifiable() {
    @Override
    public <T> void onEvent(T data) {
        User u = (User) data;
        logger.info("User name: " + u.getUsername());
    }
}));

【问题讨论】:

  • 抱歉,我不明白您的问题...您只想避免在Notifiable 实现中进行显式转换,是这样吗?另外,你能把Notifier类的代码贴出来吗?
  • 你好,我添加了相关的源代码。该解决方案有两点我不喜欢:第一件事是处理程序对象中的显式转换,因为它需要一种有效负载,我想更自然地表达这一点。第二个是,我确信我描述的更一般的逻辑有更优雅的方法,我只是不知道。

标签: java hibernate socket.io jpa-2.1 hibernate-entitymanager


【解决方案1】:

如果您想避免显式转换,请进行以下更改:

一,让你的 Notifiable 接口通用:

public interface Notifiable<T> {
    public void onEvent(T data);
}

二,让 Subscriber 类也通用:

public class Subscriber<T> {
    public String topic;
    public Notifiable<T> notifiable;
    public Subscriber(String topic, Notifiable<T> n) {
        ...
    }
 }

三、适配Notifier类

public class Notifier {
    private static Notifier instance = null;

    @SuppressWarnings("rawtypes")
    private List<Subscriber> subscribers = new ArrayList<Subscriber>();

    public Notifier() {};

    public <T> void  subscribe(String topic, Notifiable<T> n) {
        if (!this.hasSubscriber(topic, n)) {
            this.subscribers.add(new Subscriber<T>(topic, n));
        }
    }

    @SuppressWarnings("unchecked")
    public <T> void publish(String topic, T data) {
        for (Subscriber<T> s : this.subscribers) {
            if (s.topic.equals(topic)) {
                s.notifiable.onEvent(data);
            }
        }
    }

    @SuppressWarnings("unchecked")
    public <T> Boolean hasSubscriber (String topic, Notifiable<T> n) {
        for (Subscriber<T> s : this.subscribers) {
           /* XXX: Beware, is safe to compare two notifiable
            * instances by their memory addresses??
            */
           if (s.topic.equals(topic) && s.notifiable == n) {
                return true;
           }
        }
        return false;
    }

    public static Notifier getInstance() {
        if (instance == null) {
            instance = new Notifier();
        }
        return instance;
    }
}

四、Socketio Handler:

Notifier.getInstance().subscribe("user/new", (new Notifiable<User>() {
    @Override
    public void onEvent(User data) {
        logger.info("User name: " + u.getUsername());
    }
}));

【讨论】:

  • 您是否同意在这种情况下,使用原始类型是可以接受的,因为发布者和消费者对实际类型有一个隐含的合同,因此不会出现强制转换问题,并且通知程序不会使用数据本身?
  • 是的,在这里使用原始类型是可以的,因为通知程序本身并不消耗数据(如你所说)......
猜你喜欢
  • 2020-06-18
  • 1970-01-01
  • 1970-01-01
  • 2020-10-10
  • 2013-12-01
  • 2013-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多