vaadin / cdi

CDI Integration for Vaadin
Apache License 2.0
41 stars 56 forks source link

Enhancement: Support new "ViewScoped" scope to help with memory management for "one page apps" #8

Closed twadzins closed 8 years ago

twadzins commented 11 years ago

In our "one page app" using vaadin-cdi-integration, users only ever use one "ShellUi" UI class and switch between high level functional views with a MenuBar and Navigator. I believe that a consequence of this is that each view bean will live throughout the lifecycle of the UI Bean, which could eventually lead to a large session size as the user traverses the app. It would be nice to have a narrower scope, such as "ViewScoped" (modeled after the JSF 2.0 ViewScoped, which I believe is conceptually somewhat similar), such that the view and its dependent beans would be cleaned up when the Navigator switches top level views.

AdamBien commented 11 years ago

Currently we have two possibilities: the use of dependent scoped views directly injected which binds the view to the ShellUI (see integration test: CDIIntegrationWithVaadinIT#dependentScopedViewIsInstantiatedOnce) or they can be created on demand with the ViewProvider (CDIIntegrationWithVaadinIT#dependentScopedViewIsInstantiatedTwiceWithViewProvider). I would prefer the first option and measure the memory usage. Do you think it could become an issue? To test the memory behavior we could create a stress test and measure the performance.

twadzins commented 11 years ago

Adam, thanks for the reply. If I follow what you are saying, there are two current ways to inject a view onto a UI, via straight @Inject (as a dependent bean) and via a ViewProvider with a navigator. It sounds like you interpreted my concern about mem mgmt around the memory used by the basic views themselves? I'm not sure if that's what you meant, so I'll describe my concern in more detail:

My concern around memory management is more about the total "instance variable" cost of views including business objects that devs may put on these dependent views, rather than just the mem used by the plumbing of the views themselves. For instance, in a one page app a user may go to 20 different views on the same ui, where each of the view and the views sub-interactions would call some business services and those views might hold onto collections received from the backend that are used for the duration of the view sub-interactions. Under the current model, the views (created via either injection mechanism) will live for the lifetime of the view, right? Then after 20 different pages are loaded, the session might get overly large. So, I envisioned that a conversational ViewScope (that I think would generally be used at the Naviagator @VaadinView level) would provide a means for the viewB would be active from the time that, for instance, the the navigator switches from viewA to viewB. At the time the navigator switches to any other view, such as viewC, the viewB conversation would end, and be cleaned up. In this model, then only the active view (and the containing UI) would be held in memory.

Another related issue I had with trying to use dependent beans was in the way we were trying to use CDI eventing. The goal was to have a high level event such as a"ReadOnlyModeChangedEvent", which the UI or one of the dependent beans would fire, and ideally any "active" views could @Observes the event and take appropriate action (such as marking forms/fields disabled). A couple of issues came up, which made me wonder if CDI eventing is even appropriate for this usage. First, I didn't want every Observing bean in the classpath to be instantiated on a fire, which would happen since most all beans might care about the ReadOnlyModeChangedEvent, but only if they are active, so I tried using @Observes(notifyObserver = Reception.IF_EXISTS) combined with "if isAttached() {//respond to event}". However, that would not deploy, since it seems Reception.IF_EXISTS is not allowed on dependent beans. So I ended up tweaking the VaadinUi scope to be allowed to be be on non-UI objects to get the Reception.IF_EXISTS behavior. It stills feels a bit hacky, and I wonder if a non-CDI Vaadin-aware eventing model would be better (such as Wicket's componet tree eventing), where any member of the component hierarchy can fire an event, specifying where the root of the firing should occur (i.e. by default the UI and all's its attached children would be candidate observers). I'm not sure that that style of eventing is doable with CDI in an elegent way. I'm curious on your thoughts on such an eventing model...

Artur- commented 11 years ago

All CDI issues in GitHub have been moved to http://dev.vaadin.com