0

我使用 vaadin + spring IOC + google guava eventbus。Resources 建议使用 guava eventbus 作为单例。但是当我这样做时,我遇到了以下问题;

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

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

这是我期望的正常行为,因为我将 eventbus 用作单例吗?如果不是,这里发生了什么?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;
    }
}

Ps 我也在 Vaadin 犹豫我应该使用 guava eventbus 还是 guava gwt event bus?

谢谢

4

1 回答 1

3

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


您所说的自定义 Vaadin Application Scope是指此 Vaadin 插件的范围吗?

无论如何,使用原型范围的 MainController bean 和 Vaadin App 很容易重现您的情况,如下所示:

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

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 应用程序 (App#1)。
  2. 单击 App1# 按钮。
  3. 启动另一个应用程序 (App#2)。
  4. 单击 App2#按钮
  5. 使用 App#1 返回选项卡。
  6. 单击 App1# 按钮。

你会得到以下输出:

开始 SandpitApplication@75a5555a
创建 MainController@2e98f864
点击按钮 // #1
addFacetEvent in MC@2e98f864: FacetAddedEventImpl@6b527dc6{data: click-13:42:45}
MainController@2e98f864{treeTableViewBuilder: [MC@2e98f864: click-13: 42:45]}
开始 SandpitApplication@3f9e529
创建 MainController@2f8d604f
点击按钮 // #2
addFacetEvent in MC@2e98f864: FacetAddedEventImpl@36c1fc67{data: click-13:42:47}
addFacetEvent in MC@2f8d604f: FacetAddedEventImpl@36c1fc67{数据:click-13:42:47}
MainController@2f8d604f{treeTableViewBuilder: [MC@2f8d604f: click-13:42:47]}
点击按钮 // #1
MC@2e98f864 中的 addFacetEvent:FacetAddedEventImpl@42d32028{数据:click-13:42:49}
MC@2f8d604f 中的 addFacetEvent:FacetAddedEventImpl@42d32028{数据:click-13:42:49}
MainController@2e98f864{treeTableViewBuilder:[MC@2e98f864 : click-13:42:45, MC@2e98f864: click-13:42:47, MC@2e98f864: click-13:42:49]}

您现在应该看到单例EventBus正在管理两个应用程序范围的MainControllerbean,每个 bean 都在接收事件(因为它由 global 解析EventBus)。

试图猜测你想要实现什么,我会说你需要创建应用程序范围的事件总线 bean:

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

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

于 2012-04-19T12:18:40.680 回答