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

时间:2012-10-25 01:26:48

标签: jsf java-ee timer

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

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

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

当前客户投票

客户>> 网络层>> app-tier

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

希望进行网络级民意调查和推送

客户<< 网络层>> app-tier

web-tier polls app-tier如果数据已更改并代表重新加载并通知(推送)客户端更新视图

的方法:

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

  1. 托管bean中的TimerTask
    Spawning threads in a JSF managed bean for scheduled tasks using a timer
  2. 带有计划注释的附加EJB
  3. 使用TimerService的其他EJB
  4. 其他?
  5. 修改

    架构:( 3层)

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

    Architecture

1 个答案:

答案 0 :(得分:3)

根据我的经验,我可以推荐两种路线,Spring Integration和CDI Events。我建议使用Spring路由,但根据您当前的堆栈,我认为CDI events可以覆盖您。它们干净地帮助您实现Observer / Observable模式,您也可以实现层的清晰分离。我必须警告你,这种方法仅对中小用例有效。请考虑以下事项:

  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
    }
    
  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));
        }
    }
    

    在上面的代码中,我使用了Timer EJB作为我的Observer。有关EJB计时器的介绍,请参阅this。同样,Observer对象将存在于应用层

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

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

    与CDI提供的邮件过滤选项相比,上述过滤仍然非常粗糙。正如您在前面引用的教程中所看到的,您可以创建CDI限定符,以便对消息进行更精细的过滤。就像我之前所说的那样,对于大规模部署来说这有点沉重,在这种情况下,如果您要依赖它,我会建议Spring集成路径。

  4. 总之,系统的模型将是:

                One Poller(Notifier) Object (In the app layer)
                        |
                        |
                        |
                Multiple Listener Objects (In the web tier)
    ---------------------------------------------------
    |   |    |    |    |   |   |     |   |    |    |  |