我使用vaadin + spring IOC + google guava eventbus。资源建议使用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;
}
}
P.s我是否应该使用guava eventbus或guava gwt事件总线在Vaadin中犹豫不决?
由于
答案 0 :(得分:3)
简短回答:此配置中的正常和预期行为(您有三个Vaadin应用程序,因此有三个MainController
实例使用单个EventBus
进行管理。)
通过自定义Vaadin应用范围您的意思是来自this Vaadin addon的范围吗?
无论如何,使用原型范围的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.
}
执行以下操作时:
您将获得以下输出:
启动SandpitApplication @ 75a5555a
创建MainController @ 2e98f864
点击按钮//#1
MC @ 2e98f864中的addFacetEvent:FacetAddedEventImpl @ 6b527dc6 {data:click-13:42:45}
MainController @ 2e98f864 {treeTableViewBuilder:[MC @ 2e98f864:click-13:42:45]}
启动SandpitApplication @ 3f9e529
创建MainController @ 2f8d604f
点击按钮//#2
MC @ 2e98f864中的addFacetEvent:FacetAddedEventImpl @ 36c1fc67 {data:click-13:42:47}
MC @ 2f8d604f中的addFacetEvent:FacetAddedEventImpl @ 36c1fc67 {data:click-13:42:47}
MainController @ 2f8d604f {treeTableViewBuilder:[MC @ 2f8d604f:click-13:42:47]}
点击按钮//#1
MC @ 2e98f864中的addFacetEvent:FacetAddedEventImpl @ 42d32028 {data:click-13:42:49}
MC @ 2f8d604f中的addFacetEvent:FacetAddedEventImpl @ 42d32028 {data: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
正在管理两个应用程序范围的MainController
bean,每个bean都在接收事件(因为它已由全局EventBus
解析)。
试图猜测你想要实现什么,我会说你需要创建应用程序范围的事件总线bean:
<bean id="eventBus" class="com.google.common.eventbus.EventBus"
scope="vaadinApplication" />
关于P.S。:我们在Vaadin项目中广泛使用标准的Guava,不需要GWT版本。