Today, the Spring Framework was released to 4.2 RC2. In Spring 4.2, better application events and Server-Sent Event(SSE) are supported.
In this article, I’ll introduce you to the two new features.
What’s Server-Sent Event
Server-sent events (SSE) is a technology where a browser receives automatic updates from a server via an HTTP connection. The Server-Sent Events EventSource API is standardized as part of HTML5 by the W3C.
Server-sent event is a standard describing how servers can initiate data transmission toward clients once an initial client connection has been established. They are commonly used to send message updates or continuous data streams to a browser client and are designed to enhance native, cross-browser streaming through a JavaScript API called EventSource, through which a client requests a particular URL in order to receive an event stream.
Web browser support for Server-Sent Events
Browser | Supported | Notes |
---|---|---|
Internet Explorer | No | |
Mozilla Firefox | Yes | Starting with Firefox 6.0 |
Google Chrome | Yes | Starting with Chrome 6 |
Opera | Yes | Starting with Opera 11 |
Safari | Yes | Starting with Safari 5.0 |
Setup Maven
Since Spring 4.2 hasn’t been released to the Maven central repository, we need to set up our own repository.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<properties>
<spring.version>4.2.0.RC2</spring.version>
</properties>
<repositories>
<repository>
<id>Springframework Milestone</id>
<url>http://repo.spring.io/milestone</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
...
</dependencies>
...
</project>
Use Server-Sent Event in Spring Controller
First of all, let me introduce you to the basic usage of Server-Sent Event.
The Spring provide us a SseEmitter class with can return an HTTP response whose content type is text/event-stream
.
Before we start, we need to add sync-support
for Spring. To do this, you can edit the web.xml
as following.
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
Then, we can add a method in the Spring Controller.
@RequestMapping("/getRealTimeMessage.action")
public SseEmitter getRealTimeMessageAction(
HttpServletRequest request) {
SseEmitter sseEmitter = new SseEmitter();
// You can send message here
sseEmitter.send("Message #1");
return sseEmitter;
}
// Do something with sseEmitter
// You can also send message in another method
sseEmitter.send("Message #2");
// Complete Send Message
sseEmitter.complete();
Use Server-Sent Event with Message Queue
In a project, I used ActiveMQ to communicate with another process. When I receive a message from the message queue, onMessage()
method will be triggered. I want to push the message to the browser using Server-Sent Event. In this section, I’ll tell you how to do it.
First of all, let’s take a quick glance at onMessage()
method.
@Component
public class MessageReceiver implements MessageListener {
/* (non-Javadoc)
* @see javax.jms.MessageListener#onMessage(javax.jms.Message)
*/
public void onMessage(Message message) {
if ( message instanceof MapMessage ) {
final MapMessage mapMessage = (MapMessage) message;
try {
String event = mapMessage.getString("event");
Long submissionId = mapMessage.getLong("submissionId");
eventPublisher.publish(new SubmissionEvent(this, submissionId, "Message"))
} catch (JMSException ex) {
LOGGER.catching(ex);
}
}
}
/**
* New feature in Spring 4.2.
*/
@Autowired
private ApplicationEventPublisher eventPublisher;
}
Here’s the definition of SubmissionEvent
.
public class SubmissionEvent extends ApplicationEvent {
public SubmissionEvent(Object source, long submissionId, String message) {
super(source);
this.submissionId = submissionId;
this.message = message;
}
// getters and setters
private final long submissionId;
private final String message;
}
As you see, I used ApplicationEventPublisher
in the class to publish an event. This event will be caught by a listener.
@Component
public class ApplicationEventListener {
@EventListener
public void submissionEventHandler(SubmissionEvent event) throws IOException {
long submissionId = event.getSubmissionId();
String message = event.getMessage();
SseEmitter sseEmitter = sseEmitters.get(submissionId);
if ( sseEmitter == null ) {
LOGGER.warn(String.format("CANNOT get the SseEmitter for submission #%d.", submissionId));
return;
}
sseEmitter.send(message);
}
public void addSseEmitters(long submissionId, SseEmitter sseEmitter) {
sseEmitters.put(submissionId, sseEmitter);
}
/**
* The list of the objects of SseEmitter.
* The key of the map stands for submissionId.
* The value of the map is the corresponding SseEmitter object.
*/
private static Map<Long, SseEmitter> sseEmitters = new Hashtable<Long, SseEmitter>();
}
At last, register the SseEmitter
to ApplicationEventListener
in controller.
@RequestMapping("/getRealTimeMessage.action")
public SseEmitter getRealTimeMessageAction(
@RequestParam(value = "submissionId", required = true) long submissionId,
HttpServletRequest request) throws IOException {
Submission submission = submissionService.getSubmission(submissionId);
if ( submission == null ) {
throw new ResourceNotFoundException();
}
SseEmitter sseEmitter = new SseEmitter();
applicationEventListener.addSseEmitters(submissionId, sseEmitter);
return sseEmitter;
}
Try it out!
Reference
- http://stackoverflow.com/questions/31229015/sse-implementation-in-spring-rest
- https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2
- http://docs.spring.io/spring/docs/4.2.0.RC2/spring-framework-reference/htmlsingle/#mvc-ann-async-http-streaming
- https://en.wikipedia.org/wiki/Server-sent_events
The Disqus comment system is loading ...
If the message does not appear, please check your Disqus configuration.