This month’s release of Java EE 7 delivers a finalized Java WebSocket API specification, which can be leveraged with Spring and Groovy to build robust WebSocket-driven applications. Spring 4 will come with support for WebSockets, but we can utilize existing JSR-356 reference implementations to build applications with WebSocket support with any version of Spring.
Project Tyrus is a JSR-356 reference implementation that comes to the community from Oracle. Building on the specification’s standards, application developers can easily develop WebSocket applications using Project Tyrus’ robust API. Tyrus also comes with standalone server, client, and container libraries that allow developers to build WebSocket applications outside of a normal web application stack.
The examples in this post will demonstrate WebSockets from a standalone application implementation, but the concepts and code can easily be adapted to a Spring Web-MVC application, or a Grails application context, with little effort.
Project Tyrus’ Standalone Maven coordinates are:
This includes the Java WebSocket API artifacts, which can be found here:
Building WebSocket endpoints on top of JSR-356 consists of a three-step process, wherein developers must register a ServerApplicationConfig that defines ServerEndpoints with a ServerApplicationContainer. The specification also defines a Builder that allows developers to easily register a ServerEndpoint for a given path.
Classes annotated with the @ServerEndpoint annotation must provide a path, and in the ServerApplicationConfig, should be returned from the getAnnotatedEndpointClasses method. Annotated classes can also use method-level annotations to handle the different phases of the request lifecycle. Available method-level annotations are: @OnOpen, @OnMessage, @OnError, and @OnClose.
Once the ServerEndpoints are written and defined within the ServerApplicationConfig, the next step is to register them with the ServerApplicationContainer. Project Tyrus’ standalone implementation provides a Server class that developers can instantiate to bootstrap the WebSocket container.
The above code will start the server on port 8025 using the context-root /context. Paths from ServerEndpoints will be derived in that context, in a similar way as regular web application containers.
From Project Tyrus’ client module, we can get access to an instance of a ClientManager, which allows for developing the client WebSocket interaction with the server. The ClientManager can either take a concrete class that is an instance of an Endpoint, or a regular POJO annotated with @ClientEndpoint.
A simple Spock test demonstrates how to build the client/server interaction with Project Tyrus.
The key to involving Spring in the Tyrus container lies in the understanding that Tyrus maintains its own application container and is entirely separate from the Spring application context. In order to integrate Spring in the WebSocket request lifecycle, we must first give it an influence on the endpoint resolution process. Once we have the Tyrus container configured to allow Spring to resolve the endpoints, then the endpoints can be regular Spring beans, and therefore participate in the application context to benefit from features like dependency injection and scoping.
Tyrus makes use of the service locator pattern to help resolve ComponentProvider instances. A ComponentProvider is responsible for informing the Tyrus container if a class is supported by its resolution strategy, and if so to provide an instance that will be used as the endpoint. To make use of Spring’s application context, we’ll need to create a ComponentProvider implementation to help facilitate resolving endpoints from the Spring context.
In this example, beans that are wired properly by name will be resolved from the Spring application context. Since the ComponentProvider is also a participant in the application context, it must also be defined as a bean in the Spring configuration.
After the SpringComponentProvider is in place and wired appropriately to the Spring application context, we must then register it as a ComponentProvider in Tyrus’ service locator registry. To do this, we’ll simply create a file named org.glassfish.tyrus.spi.ComponentProvider and put it in the META-INF/services directory of the application’s resources. This should have a single line entry with the fully qualified class name of the SpringComponentProvider: com.company.package.SpringComponentProvider.
Now that the necessary pieces are in place, the final thing that must be done is to wire a complete Spring application context, including the Tyrus server, the SpringComponentProvider, and each endpoint that we want resolved from the Spring context. We can make use of Spring’s Java Configuration to instantiate the Tyrus server, as well as make it an autowire candidate for beans that might find it useful.