代码之家  ›  专栏  ›  技术社区  ›  Community wiki

谷歌番石榴单例事件总线多次触发

  •  0
  • Community wiki  · 技术社区  · 1 年前

    我使用vaadin+春季国际奥委会+谷歌番石榴活动巴士。参考资料建议使用guava事件总线作为singleton。但当我这样做的时候,我有以下问题;

    • 假设我同时在3个不同的浏览器上运行该应用程序,因此我的应用程序有3个不同实例。

    • 然后,例如,当我按下一个浏览器上的按钮并触发一个事件时,我注意到我的带有@subscribe注释的相关侦听器方法被调用了3次!

    这是我期望的正常行为吗?因为我使用eventbus作为singleton?如果不是,这里发生了什么?MainController是一个带有自定义Vaadin应用程序范围的spring管理bean

    class MainController{
      public MainController() throws DAOException, Exception {
        EventBusFactory.getEventBusInstance().register(this);
      }
    
      @Subscribe
      public void addFacetEvent(FacetAddedEvent event) throws DAOException {
        getTreeTableView().addToList(event.getData());
      }
    } 
    
    class EventBusFactory{
      public static EventBus getEventBusInstance() {
            if(eventBus==null){
                eventBus=new EventBus();
            }
            return eventBus;
        }
    }
    

    P.s我在Vaadin也有犹豫,我应该使用番石榴事件总线还是番石榴gwt事件总线?

    谢谢

    1 回复  |  直到 1 年前
        1
  •  3
  •   Grzegorz Rożniecki    13 年前

    简短回答:在这种配置中,这是正常的和预期的行为(您有三个Vaadin应用程序,因此有三个 MainController 使用单个管理的实例 EventBus )。


    通过 自定义Vaadin应用范围 你的意思是来自 this Vaadin addon ?

    无论如何,使用原型范围的MainController bean和Vaadin应用程序复制您的情况很简单,如下所示:

    public class SandpitApplication extends Application {
      private static final long serialVersionUID = 1L;
      private static final Logger log = Logger.getLogger(SandpitApplication.class);
    
      // https://vaadin.com/wiki/-/wiki/Main/Spring%20Integration#section-Spring+Integration-SpringContextHelperClass
      private SpringContextHelper ctx;
    
      @Override
      public void init() {
        // vaadin stuff
        setTheme("common");
        final Window mainWindow = new Window("Vaadin Sample Application");
        setMainWindow(mainWindow);
    
        // get your bean from spring
        log.info("start SandpitApplication@" + Integer.toHexString(hashCode()));
        ctx = new SpringContextHelper(this);
        // create application-wide bean
        final MainController mainController = ctx.getBean("mainController");
    
        mainWindow.addComponent(new Button("click to post", new Button.ClickListener() {
          @Override public void buttonClick(final ClickEvent event) {
            log.info("click on button");
            EventBusFactory.getEventBusInstance().post(
                new FacetAddedEventImpl("click-"
                    + new SimpleDateFormat("HH:mm:ss").format(new Date())));
            log.info(mainController);
          }
        }));
      }
    }
    

    主控制器 类别:

    class MainController {
      private static final Logger log = Logger.getLogger(MainController.class);
    
      public MainController() {
        log.info("creating MainController@" + Integer.toHexString(hashCode()));
        EventBusFactory.getEventBusInstance().register(this);
      }
    
      @Subscribe
      public void addFacetEvent(final FacetAddedEvent event) {
        final String signature = "MC@" + Integer.toHexString(hashCode()) + ": ";
        log.info("addFacetEvent in " + signature + event);
        // getTreeTableViewBuilder returns extended ArrayList with fancy add
        getTreeTableViewBuilder().addFacetToList(signature + event.getData());
      }
    
      // plus other stuff like toString etc.
    }
    

    当您执行以下操作时:

    1. 在浏览器中启动vaadin应用程序(应用程序#1)。
    2. 单击App1#按钮。
    3. 启动另一个应用程序(应用程序#2)。
    4. 单击App2#按钮
    5. 使用应用程序#1返回标签页。
    6. 单击App1#按钮。

    您将得到以下输出:

    开始SandpitApplication@75a5555a
    创建MainController@2e98f864
    点击按钮//#1
    在中添加FacetEventMC@2e98f864以下为:FacetAddedEventImpl@6b527dc6{数据:点击-13:42:45}
    MainController@2e98f864{treeTableViewBuilder:[MC@2e98f864:单击-13:42:45]}
    开始SandpitApplication@3f9e529
    创建MainController@2f8d604f
    点击按钮//#2
    在中添加FacetEventMC@2e98f864以下为:FacetAddedEventImpl@36c1fc67{数据:点击-13:42:47}
    在中添加FacetEventMC@2f8d604f以下为:FacetAddedEventImpl@36c1fc67{数据:点击-13:42:47}
    MainController@2f8d604f{treeTableViewBuilder:[MC@2f8d604f:单击-13:42:47]}
    点击按钮//#1
    在中添加FacetEventMC@2e98f864以下为:FacetAddedEventImpl@42d32028{数据:点击-13:42:49}
    在中添加FacetEventMC@2f8d604f以下为:FacetAddedEventImpl@42d32028{数据:点击-13:42:49}
    MainController@2e98f864{treeTableViewBuilder:[MC@2e98f864:点击-13:42:45,MC@2e98f864:点击-13:42:47,MC@2e98f864:单击-13:42:49]}

    您现在应该看到那个singleton 事件总线 正在管理两个应用程序范围 主控制器 beans,并且每个都在接收事件(因为它由全局 事件总线 )。

    试着猜测您想要实现什么,我认为您需要创建应用程序范围的事件总线bean:

    <bean id="eventBus" class="com.google.common.eventbus.EventBus"
        scope="vaadinApplication" />
    

    关于P.S.:我们在Vaadin项目中广泛使用标准Guava,不需要GWT版本。