9

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

这还不够,因为有太多流量被发送到客户端,而且现在 primefaces 支持服务器推送,我只想重新加载数据并将其推送到客户端视图(如果数据已更改)。

这应该通过从 Web 层轮询到应用程序层调用类似hasChanged(...). 如果数据发生更改,Web 层会向客户端推送通知以重新加载数据。

当前客户投票

客户端>>网络层>>应用层

客户端通过 ajax 向 web 层请求数据,再次向应用层请求数据并更新视图

希望网络层投票和推送

客户端<<网络层>>应用层

网络层轮询应用层数据是否已更改并代表重新加载并通知(推送)客户端更新视图

方法:

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

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

编辑:

架构:(3层)

  • Server1:数据库
  • Server2:应用层(EAR 与远程 EJB + Hibernate)
  • Server3:网络层(使用 JSF 2.0 + Primefaces 3.4 的 WAR)
  • 客户端:浏览器

建筑学

4

1 回答 1

3

根据我的经验,我可以推荐两条路线,Spring Integration 和 CDI Events。我推荐 Spring 路线,但根据您当前的堆栈,我认为CDI 事件已经涵盖了您。它们干净利落地帮助您实现 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));
        }
    }
    

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

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

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

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

总之,系统的模型将是:

            One Poller(Notifier) Object (In the app layer)
                    |
                    |
                    |
            Multiple Listener Objects (In the web tier)
---------------------------------------------------
|   |    |    |    |   |   |     |   |    |    |  |  
于 2012-10-30T05:32:17.027 回答