在ManagedBean中进行远程轮询,并通过push通知客户端视图

djm*_*jmj 9 jsf timer java-ee

我有一个jsf视图,它显示了一个远程检索的表中的托管bean(viewscope)的一些数据.
目前,使用primefaces poll组件通过客户端视图轮询更新数据.

这还不够,因为要向客户端发送大量流量,现在Primefaces支持服务器推送我只想重新加载数据并在数据发生变化时将其推送到客户端视图.

这应该通过从Web层到应用层的轮询来实现,调用类似的方法hasChanged(...).如果数据已更改,则Web层会将通知推送到客户端以重新加载数据.

当前的客户投票

客户端>> web-tier >> app-tier

客户端通过ajax向web层询问数据,该数据再次向app-tier请求数据和更新视图

希望网络层轮询和推送

客户端<< web-tier >> app-tier

如果数据已更改并代表重新加载并通知(推送)客户端更新视图,则web-tier轮询应用层

处理办法:

在Web层中实现托管bean轮询的最佳方法是什么?

  1. 托管bean中的TimerTask
    使用计时器生成用于计划任务的JSF托管bean中的线程
  2. 带有Schedule注释的附加EJB
  3. 使用TimerService的附加EJB
  4. 其他?

编辑:

架构:(3层)

  • Server1:数据库
  • Server2:app-tier(带远程EJB + Hibernate的EAR)
  • Server3:web-tier(带有JSF 2.0 + Primefaces 3.4的WAR)
  • 客户端:浏览器

建筑

kol*_*sus 3

根据我的经验,我可以推荐两条路线:Spring Integration 和 CDI Events。我推荐 Spring 路线,但根据您当前的堆栈,我认为CDI 事件已经涵盖了您。它们干净地帮助您实现观察者/可观察模式,并且您也可以清晰地分离层。但我必须警告您,这种方法仅对中小型用例有效。考虑以下:

  1. 设计并实现一个Event类,该类封装了需要传递给消费者的所有信息。我们将其称为FundsTransfer事件 您的事件实现应该包含足够的信息,以使侦听器仅过滤感兴趣的事件。一个简单的 POJO

    class FundsTransfer {
    
        BigDecimal transferValue;
        Date transferDate;
        int transferCurrencyCode;
    
        public FundsTransfer(BigDecimal transferValue, Date date, int currencyCode) {
            //set accordingly
        }
        //setters and getters
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在业务层实现一个业务对象,称之为Notifier。轮询的功能应该委托给这个对象。它将负责创建和发布类型对象event以响应服务器端的更改。根据您的要求,该对象可以是处理所有Event类型的单例,也可以有一组Notifier轮询不同事件的类型。

    //A sample implementation of your Observer object :
    @Singleton //Defines a singleton EJB
    public class PollerService {
    
        @Inject
        Event fundsTranferNotifier;
    
        //this annotation specifies that the polling method should run every second.
        @Schedule(second = "*/1", minute = "*", hour = "*", persistent = false)
        public void pollIt() {
            boolean found = this.pollingMethod(); // pollingMethod() will do the actual polling
            if (found) {     //based on the outcome of the polling method, fire the notifier  method
                blowWhistleOnTransfer();
            }
        }
    
        public void blowWhistleOnTransfer() {
            //this is the broadcast event.
            fundsTransferNotifier.fire(new FundsTransfer(new BigDecimal("100000", new Date(), 855));
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    在上面的代码中,我使用了TimerEJB 作为我的观察者。有关 EJB 计时器的介绍,请参阅此内容。同样,该Observer对象将驻留在应用程序层中

  3. 每个客户端层都可以访问一个侦听器对象,当感兴趣的事件发生(即已由某个Notifier类型发布)时,该侦听器对象将收到通知。然后监听器可以push根据这个事件发出一个。您的侦听器对象可以是带有 CDI 注释的 POJO @Named。在您的侦听器对象中,只需使用注释实现一个方法@Observes,并使用侦听器感兴趣的事件类型的参数:

    public void onNewTransfer(@Observes FundsTransfer transfer) {
        if (transfer.compareTo(new BigDecimal("150000")) > 0) {
            //push to view.
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    与 CDI 提供的消息过滤选项相比,上述过滤仍然相当粗糙。正如您从我之前引用的教程中看到的,您可以创建 CDI 限定符来对消息进行更细粒度的过滤。就像我之前所说的那样,这对于大规模部署来说有点繁重,在这种情况下,如果您愿意依赖的话,我建议您使用 spring 集成路线。

综上所述,系统的模型为:

            One Poller(Notifier) Object (In the app layer)
                    |
                    |
                    |
            Multiple Listener Objects (In the web tier)
---------------------------------------------------
|   |    |    |    |   |   |     |   |    |    |  |  
Run Code Online (Sandbox Code Playgroud)