Server Sent Events (SSE) with Spring Framework (Pt. I) by rfvallina

Posted Jun 26, 2017 in Java Spring SSE HTML5

The idea behind Server Sent Events (SSEs) may be familiar: a web app “subscribes” to a stream of updates generated by a server and, whenever a new event occurs, a notification is sent to the client.

Why would you choose SSE over traditional Ajax requests?

Polling is used very often in Ajax applications when a client makes a request and waits for a response. When this is done repeateadly because you need continuous updates from the server it generates an HTTP overhead, so here is where SSE becomes an efficient solution.

Why would you choose SSE over WebSockets?

SSE is one-way messaging and WebSockets are bi-directional. WebSockets provide a richer mechanism to perform full-duplex communication but they also require a special protocol so it’s something more complex to setup. However, SSE requests are sent over traditional HTTP and they do not require a special protocol or server setup to get it working. And there are cases where you only need updates from the server and client doesn’t need to send any data, so SSE becomes the perfect alternative.

Examples where SSE fits good

News feeds, push notifications, status updates,… In the next article (that I’ll publish in the next few days) we we’ll see a real use case that I had to implement in a project and where SSE was a perfect choice.

Here is a nice article which explains the concept of SSE pretty well.

SSE with Spring

There was no support for SSE in Spring Framework until version 4.2 (mid 2015). Yes, now you are thinking ‘Wow, this is very late, since SSE became available in HTML5 back in 2009-2010’ (See W3 specification). Not only that, IE browser doesn’t yet support SSE. You’re kidding me, right?

The good thing is that in latest Spring releases you can implement SSE very easily. The stuff involved in Spring is the emitter, the event publisher, the event listener and the event object.

SseEmitter

SseEmitter is a specialization of ResponseBodyEmitter for sending Server-Sent Events. You should return this object in your REST operation and the Spring controller will automatically return the necessary ‘text/event-stream’ Content-Type header.

@Controller
public class ItemsFeedController extends AbstractController {

	@GetMapping("/feed")
	public SseEmitter getResults() {
		
		String eventId = UUID.randomUUID().toString();
		SseEmitter emitter = new SseEmitter(30000L);
		sseEngine.getEmitters().put(eventId, emitter);

		//Push feed data
		...

		return emitter;
	}

}

Event Listener

Application events are available since the very beginning of the Spring framework as a mean for loosely coupled components to exchange information. But all this has been improved in Spring 4.2. You simply need to use the annotation @EventListener and no extra configuration is needed. In case you have different event listeners for each type of notification you can define a SpEL expression that should match in order to handle the event.

	@EventListener(classes = ResultsEvent.class)
	public void onPublish(AbstractApplicationEvent event) {
		ResultsEvent resultsEvent = (ResultsEvent) event;
		SseEmitter emitter = sseEngine.getEmitters().get(event.getEventId());
		try {
			if (!resultsEvent.getItems().isEmpty()) {
				emitter.send(resultsEvent.getItems());
			}
		} catch (IOException e) {
			logger.error("Error in emitter {} while sending message", emitter);
			sseEngine.getEmitters().remove(event.getEventId());
		}

	}

Event Publisher

ApplicationEventPublisher is the interface that encapsulates event publication functionality. You can simply inject this interface into your service so that you are able to publish events that will be listened by the event listeners.

	public void publish(SseData sseData) {
		ResultsSseData serviceData = (ResultsSseData) sseData;
		//Do the necessary tasks with the sse data
		...

		//Publish the event
		applicationEventPublisher.publishEvent(new ResultsEvent(this, serviceData.getEventId(), items));
	}

Application Events

ApplicationEvent is the abstract class to be extended by all application events. You will create new event classes with the necessary data to be published.

	public class MyApplicationEvent extends ApplicationEvent {

		private String message;
		private String eventId;

		//Constructor

		//Getters and Setters
	}

Hopefully you now have a better understanding of what SSEs are and you are familiar with the backend stuff necessary to implement this using Spring Framework.

In the next article we we’ll see a real use case and a clean approach to handle SSEs.


Comments