When you write a WebSocket application using the Jetty WebSocket APIs, your code typically need to depend on just the Jetty WebSocket APIs to compile your application. However, at runtime you need to have the implementation of the Jetty WebSocket APIs in your class-path (or module-path).
Jetty’s WebSocket APIs are provided by the following Maven artifact:
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-jetty-api</artifactId>
<version>{version}</version>
</dependency>
Jetty’s implementation of the Jetty WebSocket APIs is provided by the following Maven artifact (and its transitive dependencies):
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-jetty-server</artifactId>
<version>{version}</version>
</dependency>
Note
|
The |
To configure correctly your WebSocket application based on the Jetty WebSocket APIs, you need two steps:
-
Make sure that Jetty sets up an instance of
JettyWebSocketServerContainer
. -
Use the
JettyWebSocketServerContainer
APIs in your applications to register your WebSocket endpoints that implement your application logic.
Jetty sets up a JettyWebSocketServerContainer
instance using JettyWebSocketServletContainerInitializer
.
When you deploy web applications using WebAppContext
, then JettyWebSocketServletContainerInitializer
is automatically discovered and initialized by Jetty when the web application starts, so that it sets up the JettyWebSocketServerContainer
.
In this way, you do not need to write any additional code:
link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]
On the other hand, when you deploy web applications using ServletContextHandler
, you have to write the code to ensure that the JettyWebSocketServletContainerInitializer
is initialized, so that it sets up the JettyWebSocketServerContainer
:
link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]
Calling JettyWebSocketServletContainerInitializer.configure(...)
must be done before the ServletContextHandler
is started, and configures the Jetty WebSocket implementation for that web application context.
Once you have setup the JettyWebSocketServerContainer
, you can configure your WebSocket endpoints.
Differently from the configuration of standard WebSocket endpoints, WebSocket endpoint classes may be annotated with Jetty WebSocket API annotations, or extend the org.eclipse.jetty.websocket.api.WebSocketListener
interface, but they are not automatically discovered, not even when deploying web applications using WebAppContext
.
Important
|
When using the Jetty WebSocket APIs, WebSocket endpoints must always be explicitly configured. |
There are two ways of configuring WebSocket endpoints when using the Jetty WebSocket APIs:
-
Using
JettyWebSocketServerContainer
, which is very similar to how WebSocket endpoints are configured when using the standardjavax.websocket
APIs, but also provides APIs to perform a direct, programmatic, WebSocket upgrade. -
Using
JettyWebSocketServlet
, which may configured inweb.xml
, rather than in Java code.
To register WebSocket endpoints using the Jetty WebSocket APIs you need to access the JettyWebSocketServerContainer
APIs.
The JettyWebSocketServerContainer
instance is stored in the ServletContext
, so it can be retrieved when the ServletContext
is initialized, either from a ServletContextListener
or from a HttpServlet
:
link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]
link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]
You can also use this variant to set up the JettyWebSocketServerContainer
and configure the WebSocket endpoints in one step:
link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]
When the ServletContextHandler
is started, the Configurator
lambda (the second parameter passed to JettyWebSocketServletContainerInitializer.configure(...)
) is invoked and allows you to explicitly configure the WebSocket endpoints using the Jetty WebSocket APIs provided by JettyWebSocketServerContainer
.
Under the hood, the call to JettyWebSocketServerContainer.addMapping(...)
installs the org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter
, which is the component that intercepts HTTP requests to upgrade to WebSocket, described in this section.
For more information about the WebSocketUpgradeFilter
see also this section.
One last alternative to register your WebSocket endpoints is to use a programmatic WebSocket upgrade via JettyWebSocketServerContainer.upgrade(...)
, which allows you to use a standard HttpServlet
subclass (rather than a JettyWebSocketServlet
as explained in this section) to perform a direct WebSocket upgrade when your application logic demands so:
link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]
link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]
When using JettyWebSocketServerContainer.upgrade(...)
, the WebSocketUpgradeFilter
is not installed, since the WebSocket upgrade is performed programmatically.
An alternative way to register WebSocket endpoints using the Jetty WebSocket APIs is to use a JettyWebSocketServlet
subclass (or even many different JettyWebSocketServlet
subclasses).
This method has the advantage that it does not install the WebSocketUpgradeFilter
under the hood, because the WebSocket upgrade is handled directly by your JettyWebSocketServlet
subclass.
This may also have a performance benefit for non-WebSocket HTTP requests (as they will not pass through the WebSocketUpgradeFilter
).
Your JettyWebSocketServlet
subclass may be declared and configured either in code or in web.xml
.
Declaring your JettyWebSocketServlet
subclass explicitly in code or in web.xml
also simplifies the declaration and configuration of other web components such as other Servlets and/or Filters (for example, it is easier to configure the CrossOriginFilter
, see also this section for more information).
For example, your JettyWebSocketServlet
subclass may be declared in code in this way:
link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]
link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]
Note how in the call to JettyWebSocketServletContainerInitializer.configure(...)
the second parameter is null
, because WebSocket endpoints are not created here, but instead by one (or more) JettyWebSocketServlet
subclasses.
Yet the call is necessary to create other WebSocket implementation components that are necessary also when using JettyWebSocketServlet
subclasses.
An HTTP upgrade request to WebSocket that matches your JettyWebSocketServlet
subclass path mapping (specified above via ServletContextHandler.addServlet(...)
) arrives at the Servlet and is inspected to verify whether it is a valid upgrade to WebSocket.
If the HTTP request is a valid upgrade to WebSocket, JettyWebSocketServlet
calls configure(JettyWebSocketServletFactory factory)
that you have overridden in your subclass, so that your application can instantiate and return the WebSocket endpoint.
After having obtained the WebSocket endpoint, JettyWebSocketServlet
performs the WebSocket upgrade.
From this point on, the communication happens with the WebSocket protocol, and HTTP components such as Filters and Servlets are not relevant anymore.
If the HTTP request is not an upgrade to WebSocket, JettyWebSocketServlet
delegates the processing to the superclass, javax.servlet.HttpServlet
, which in turn invokes methods such as doGet(...)
or doPost(...)
depending on the HTTP method.
If your JettyWebSocketServlet
subclass did not override the doXYZ(...)
method corresponding to the HTTP request, a 405 Method Not Allowed
response is returned to the client, as per the standard HttpServlet
class implementation.
Note
|
It is possible to use both However, it is typically best to avoid mixing the use of |
Using JettyWebSocketServerContainer.addMapping(...)
will install the WebSocketUpgradeFilter
under the hood, which by default will intercepts all HTTP requests to upgrade to WebSocket.
However, as explained in this section, if WebSocketUpgradeFilter
does not find a matching WebSocket endpoint for the request URI path, then the HTTP request is passed to the Filter chain of your web application and may arrive to your JettyWebSocketServlet
subclass, where it would be processed and possibly result in a WebSocket upgrade.