Spring-MVC,Cometd:没有@Listener 的广播

Spring-MVC, Cometd : Broadcasting without @Listener

我正在开发一个 Spring-MVC 应用程序,感谢 SO 上的用户,我们已经有了一个可用的 Cometd 聊天功能。我们在应用程序中拥有的另一个功能是通知,但我们希望在实时通知发生时立即集成它们,有点像 Facebook 的功能。

基本上这个想法是,无论何时创建新通知,它都会保存在数据库中,并且来自后端的信息必须通过每个用户的唯一通道传递给登录用户的通知。

我想知道这种方法是否有效,因为我需要做一些工作才能将通知路由到聊天 class。请注意,我也没有 ChatServiceImpl class 的接口。可以吗?说的够多了,这是代码:

聊天服务实现:

@Named
@Singleton
@Service
public class ChatServiceImpl {
    @Inject
    private BayeuxServer bayeux;

    @Session
    private ServerSession serverSession;


    public void sendNotification(Notification notification,int id
// And then I send notification here like below, by extracting information from the notification object.

 ServerChannel serverChannel = bayeux.createChannelIfAbsent("/person/notification/" + id).getReference();
        serverChannel.setPersistent(true);
        serverChannel.publish(serverSession, output);
        }
    }

上面的class没有接口,所以我打算用下面的方法:

@Service
@Transactional
public class GroupCanvasServiceImpl implements GroupCanvasService{
    private ChatServiceImpl chatService;

   public void someMethod(){
   chatService.sendNotification(notification, id);
}
}

BayeuxInitializer :

@Component
public class BayeuxInitializer implements DestructionAwareBeanPostProcessor, ServletContextAware
{
    private BayeuxServer bayeuxServer;
    private ServerAnnotationProcessor processor;

    @Inject
    private void setBayeuxServer(BayeuxServer bayeuxServer)
    {
        this.bayeuxServer = bayeuxServer;
    }

    @PostConstruct
    private void init()
    {

        this.processor = new ServerAnnotationProcessor(bayeuxServer);
    }

    @PreDestroy
    private void destroy()
    {
        System.out.println("Bayeux in PreDestroy");
    }

    public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException
    {
        processor.processDependencies(bean);
        processor.processConfigurations(bean);
        processor.processCallbacks(bean);
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String name) throws BeansException
    {
        return bean;
    }

    public void postProcessBeforeDestruction(Object bean, String name) throws BeansException
    {
        processor.deprocessCallbacks(bean);
    }

    @Bean(initMethod = "start", destroyMethod = "stop")
    public BayeuxServer bayeuxServer()
    {
        return new BayeuxServerImpl();
    }

    public void setServletContext(ServletContext servletContext)
    {
        servletContext.setAttribute(BayeuxServer.ATTRIBUTE, bayeuxServer);
    }
}

请告诉我这种方法是否合适。非常感谢。

@Listener 注释适用于处理从远程客户端接收的消息的方法。

如果你只需要发送服务器到客户端的消息,你不需要严格地用@Listener注释任何方法:你检索你想要的ServerChannel就足够了发布到,并使用它来发布消息。

在您的特定情况下,您似乎并不真的需要在多个订阅者的频道上广播消息,但您只需要向特定客户端发送消息,由 id参数。

如果是这种情况,那么以这种方式使用点对点消息传递可能会更好:

public void sendNotification(Notification notification, int id)
{
    ServerSession remoteClient = retrieveSessionFromId(id);
    remoteClient.deliver(serverSession, "/person/notification", notification);
}

此解决方案的优点是可以创建更少的频道(您不需要每个 id 频道)。

更好的是,您可以用 /service/notification 等服务频道替换 /person/notification 频道(这是一个广播频道)。 这样一来,就很明显了,用来传递通知的通道是用于点对点通信的(因为服务通道不能用来广播消息)。

retrieveSessionFromId() 方法是您必须在用户登录时映射的方法,例如,请参阅有关 CometD authentication 的文档。