Application Lifecycle
In this section, we look into more technical details of application deployment, user sessions, and UI instance lifecycle. These details are not generally needed for writing Vaadin applications, but may be useful for understanding how they actually work and, especially, in what circumstances their execution ends.
Deployment
Before a Vaadin application can be used, it has to be deployed to a Java web
server. Deploying reads the servlet classes annotated with the
@WebServlet annotation or the web.xml
deployment descriptor in the application to register servlets for
specific URL paths and loads the classes. Deployment does not yet normally run
any code in the application, although static blocks in classes are executed when
they are loaded.
There is no need to define your own servlet class (which should extend
the VaadinServlet
class) if you are using Servlet 3.0 specification. You just need
to have at least one class annotated with @Route
annotation and a
VaadinServlet
instance will be registered for you automatically and Vaadin will
register all servlets required automatically.
Automatic servlet registration
When starting, Vaadin application tries to registed the following servlets:
-
Vaadin application servlet, mapped to
/*
path
This servlet is needed to serve the main application files.
The servlet won’t be registered, if any VaadinServlet
is registered already
or if there is no class annotated with Route
annotation.
-
Frontend files servlet, mapped to
/frontend/*
path
This servlet is required in the development mode to serve the WebJar contents and is only registered when the application is started in the development mode.
In addition to the rules mentioned above, a servlet won’t be registered, if
* there is a servlet that had been mapped to the same path already
* or if disable.automatic.servlet.registration
system property is set to true
Undeploying and Redeploying
Applications are undeployed when the server shuts down, during redeployment, and when they are explicitly undeployed. Undeploying a server-side Vaadin application ends its execution, all application classes are unloaded, and the heap space allocated by the application is freed for garbage-collection.
If any user sessions are open at this point, the client-side state of the UIs is left hanging and an Out of Sync error is displayed on the next server request.
Vaadin Servlet and Service
The VaadinServlet
receives all server requests mapped to it by its URL, as defined in the
deployment configuration, and associates them with sessions. The sessions
further associate the requests with particular UIs.
When servicing requests, the Vaadin servlet handles all tasks common
to servlets in a VaadinService
. It manages
sessions, gives access to the deployment configuration information, handles
system messages, and does various other tasks. Any further servlet
specific tasks are handled in the corresponding
VaadinServletService
. The
service acts as the primary low-level customization layer for processing
requests.
Customizing Vaadin Servlet
Many common configuration tasks need to be done in the servlet class, which you
already have if you are using the @WebServlet annotation for
Servlet 3.0 to deploy the application. You can handle most customization by
overriding the servletInitialized()
method, where the
VaadinService
object is available with getService()
(it would not be available in a constructor). You should always call
super.servletInitialized()
in the beginning.
public class MyServlet extends VaadinServlet {
@Override
protected void servletInitialized() throws ServletException {
super.servletInitialized();
//...
}
}
To add custom functionality around request handling, you can override the
service()
method.
User Session
A user session begins when a user first makes a request to a Vaadin servlet
by opening the URL for a particular UI
. All server requests
belonging to a particular UI class are processed by the
VaadinServlet
class. When a new
client connects, it creates a new user session, represented by an instance of
VaadinSession
. Sessions are tracked using cookies stored in the
browser.
You can obtain the VaadinSession
of a UI
with
getSession()
or globally with
VaadinSession.getCurrent()
. It also provides access to the
lower-level session objects, HttpSession
, through a WrappedSession
. You can
also access the deployment configuration through VaadinSession
.
A session ends after the last UI
instance expires or is closed, as
described later.
Handling Session Initialization and Destruction
You can handle session initialization and destruction by implementing a
[interfacename]`SessionInitListener or SessionDestroyListener
,
respectively, to the VaadinService
.
You can do that best by extending [classname]`VaadinServlet and overriding the
servletInitialized()
method, as outlined in
Vaadin Servlet and Service.
public class MyServlet extends VaadinServlet
implements SessionInitListener, SessionDestroyListener {
@Override
protected void servletInitialized() throws ServletException {
super.servletInitialized();
getService().addSessionInitListener(this);
getService().addSessionDestroyListener(this);
}
@Override
public void sessionInit(SessionInitEvent event)
throws ServiceException {
// Do session start stuff here
}
@Override
public void sessionDestroy(SessionDestroyEvent event) {
// Do session end stuff here
}
}
Loading a UI
When a browser first accesses a URL mapped to the servlet of a particular UI class, the Vaadin servlet generates a loader page. The page loads the client-side engine (widget set), which in turn loads the UI in a separate request to the Vaadin servlet.
A UI
instance is created when the client-side engine makes its
first request.
Once a new UI is created, its [methodname]`init() method is called. The method
gets the request as a VaadinRequest
.
Customizing the Loader Page
The HTML content of the loader page is generated as an HTML DOM object, which
can be customized by implementing a BootstrapListener
that
modifies the DOM object. To do so, you need to extend the
VaadinServlet
and add a SessionInitListener
to the
service object, as outlined in User Session. You can then
add the bootstrap listener to a session with
addBootstrapListener()
when the session is initialized.
Loading the widget set is handled in the loader page with functions defined in a
separate BootstrapHandler.js
script whose content is inlined into the page.
UI Expiration
UI
instances are cleaned up if no communication is received from
them after some time. If no other server requests are made, the client-side
sends keep-alive heartbeat requests. A UI is kept alive for as long as requests
or heartbeats are received from it. It expires if three consecutive heartbeats
are missed.
The heartbeats occur at an interval of 5 minutes, which can be changed with the
heartbeatInterval parameter of the servlet. You can configure the
parameter in @VaadinServletConfiguration
or in web.xml
.
When the UI cleanup happens, a DetachEvent
is sent to all
`DetachListener##s added to the UI. When the [classname]`UI
is
detached from the session, detach()
is called for it.
Closing UIs Explicitly
You can explicitly close a UI with [methodname]`close(). The method marks the UI to be detached from the session after processing the current request. Therefore, the method does not invalidate the UI instance immediately and the response is sent as usual.
Detaching a UI does not close the page or browser window in which the UI is running and further server request will cause error. Typically, you either want to close the window, reload it, or redirect it to another URL. If the page is a regular browser window or tab, browsers generally do not allow closing them programmatically, but redirection is possible. You can redirect the window to another URL via JS execution.
If you close other UI than the one associated with the current request, they will not be detached at the end of the current request, but after next request from the particular UI. You can make that occur quicker by making the UI heartbeat faster or immediately by using server push.
Session Expiration
A session is kept alive by server requests caused by user interaction with the application as well as the heartbeat monitoring of the UIs. Once all UIs have expired, the session still remains. It is cleaned up from the server when the session timeout configured in the web application expires.
If there are active UIs in an application, their heartbeat keeps the session alive indefinitely. You may want to have the sessions timeout if the user is inactive long enough, which is the original purpose of the session timeout setting. If the closeIdleSessions deployment configuration parameter of the servlet is set to true the session and all of its UIs are closed when the timeout specified by the session-timeout parameter of the servlet expires after the last non-heartbeat request. Once the session is gone, the browser will show an Out Of Sync error on the next server request.
See Runtime Configuration about setting configuration parameters.
You can handle session expiration on the server-side with a [interfacename]`SessionDestroyListener, as described in User Session.
Closing a Session
You can close a session by calling [methodname]`close() on the
VaadinSession
. It is typically used when logging a user out and the
session and all the UIs belonging to the session should be closed. The session
is closed immediately and any objects related to it are not available after
calling the method.
@Route("")
public class MainLayout extends Div {
protected void onAttach(AttachEvent attachEvent) {
UI ui = getUI().get();
Button button = new Button("Logout", event -> {
// Redirect this page immediately
ui.getPage().executeJs("window.location.href='logout.html'");
// Close the session
ui.getSession().close();
});
add(button);
// Notice quickly if other UIs are closed
ui.setPollInterval(3000);
}
}
This is not enough. When a session is closed from one UI, any other UIs attached to it are left hanging. When the client-side engine notices that a UI and the session are gone on the server-side, it displays a "Session Expired" message and, by default, reloads the UI when the message is clicked.
9CD47610-3DF6-416E-B7D4-1128DCA93B6A