Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.
See all our reports

Adding WebSocket endpoints on the fly with JRebel and Spring Boot

Enough REST! Leap by switching to WebSockets with JRebel and Spring Boot

REST and RESTful web services are awesome with a number of benefits, though WebSockets are on a whole new level and solve a number of problems that RESTful HTTP really can’t. The number one benefit of WebSockets is that fast full duplex bi-directional communication channel, that will deliver all your goods with lightning speeds, making all your RESTing buddies seem like a herd of snails traveling through peanut butter. If you’d like to see the numbers behind the claim you can take a look at these comparison benchmarks.

While Spring in general is the most popular java web framework out there, it’s also one of the largest and most feature-rich frameworks. It’s quite easy to get lost in the Spring Universe and forget why you even set off to write some code in the first place. Spring Boot is a project created to make sure you never get lost and even gives a helpful nudge now and then to speed you along. It consists of Starter POMs, which you can easily add to your project to add another piece from the Spring Universe, while not worrying about dependency versions and keeping your sanity.

And finally to rocket propel us forward, we’re going to use JRebel to make changes on the fly without waiting for Spring Boot to restart. JRebel replaces code in the running JVM and integrates with Spring and over 80 other frameworks, so you can view code changes instantly.

FOLLOW ALONG WITH JREBEL NOW

To bootstrap our next billion-dollar-enterprise application with WebSockets head on to http://start.spring.io/ to generate the Spring Boot project skeleton. Fill in whatever values you want for group/artifact/name fields, but make sure to select Websocket as one of your project dependencies. Hit “Generate project” and you’re already halfway done.

spring_boot_generator

As we’re going to also serve some static html files, let’s add a webapp folder under src/main with the following simple index.html:

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>

spring_boot_blog_structure
Here’s a picture to frame and marvel – the initial project structure of your billion-dollar-enterprise app:

We’re now ready to fire up our app for the first time. In the previous Spring Boot blog post, Simon showed you how to run a Boot app with JRebel via the main method of the Application class. Another popular option is to run it with the command mvn spring-boot:run using the Spring Boot Maven plugin. To enable JRebel in this case we need to manually configure the jvmArgument to point to the JRebel native agent, so that the embedded tomcat will have JRebel attached:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <jvmArguments>-agentpath:/Users/poolik/jrebel/lib/libjrebel64.dylib</jvmArguments>
    </configuration>
</plugin>

Now type

mvn spring-boot:run

and you’ll see your app start up with the JRebel agent:

2014-11-24 23:50:58 JRebel:  #############################################################
2014-11-24 23:50:58 JRebel:
2014-11-24 23:50:58 JRebel:  JRebel Agent 6.0.0 (201410311626)
2014-11-24 23:50:58 JRebel:  (c) Copyright ZeroTurnaround AS, Estonia, Tartu.
2014-11-24 23:50:58 JRebel:
2014-11-24 23:50:58 JRebel:
2014-11-24 23:50:58 JRebel:  License acquired from License Server: http://raven.jc.zt:8999
2014-11-24 23:50:58 JRebel:
2014-11-24 23:50:58 JRebel:  Licensed to ZeroTurnaround.
2014-11-24 23:50:58 JRebel:
2014-11-24 23:50:58 JRebel:
2014-11-24 23:50:58 JRebel:  #############################################################
...
2014-11-24 23:51:05.913  INFO 76613 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080/http
2014-11-24 23:51:05.920  INFO 76613 --- [           main] demo.Application                         : Started Application in 6.823 seconds (JVM running for 13.595)

Open up http://localhost:8080/ in your browser and you’ll see the glorious “Hello World”.

Next step, let’s add some meat to our index.html file. For demo purposes I’ve half baked a simple index.html to connect to and send/receive messages via websockets, copy the contents of https://gist.github.com/poolik/cfc3ac060b308e155290 to index.html. Now refresh your browser and you should see the following form:
spring_boot_blog_form

Try hitting connect, but unfortunately it will just print out a error to the Javascript console, because no WebSocket endpoint is defined on our server. Let’s fix that by adding the following two simple bean definitions to Application.java:

@Bean
public EchoEndpoint echoEndpoint() {
    return new EchoEndpoint();
}
@Bean
public ServerEndpointExporter serverEndpointExporter() {
    return new ServerEndpointExporter();
}
</java>

And of course we need to create the EchoEndpoint itself:

@ServerEndpoint(“/echo”)
public class EchoEndpoint {
  private static final Logger log = LoggerFactory.getLogger(EchoEndpoint.class);

  @OnOpen
  public void onWebSocketConnect(Session session) {
    log.info("Connected with: " + session.getId());
  }
  @OnMessage
  public void onWebSocketMessage(Session session, String message) {
    log.info("Message (from " + session.getId() + "): " + message);
  }
  @OnClose
  public void onWebSocketClose(Session session) {
    log.info("Closed: " + session.getId());
  }
  @OnError
  public void onWebSocketError(Session session, Throwable error) {
    log.info("Error (from " + session.getId() + "): " + error.getMessage());
  }
}

Let’s recompile our changes and refresh the browser. We see that JRebel reloads the class demo.Application and adds two new beans:

2014-11-25 00:02:24 JRebel: Reloading class 'demo.Application'.
...
2014-11-25 00:02:24 JRebel-Spring: Adding bean 'serverEndpointExporter'
2014-11-25 00:02:24 JRebel-Spring: Adding bean 'echoEndpoint'

And indeed, if we now click connect we see that the connection is successful and we can send messages to the server:

2014-11-25 00:03:16.676  INFO 76613 --- [nio-8080-exec-8] demo.EchoEndpoint                        : Connected with: 0
2014-11-25 00:05:39.835  INFO 76613 --- [nio-8080-exec-9] demo.EchoEndpoint                        : Message (from 0): Here is a message!

But unfortunately we’re not really taking advantage of that awesome bi-directional channel mentioned earlier, because we only use it for one way communication. Let’s fix that by making our endpoint echo every message it receives, by changing the onWebSocketMessage to the following:

@OnMessage
public void onWebSocketMessage(Session session, String message) throws IOException {
  log.info("Message (from " + session.getId() + "): " + message);
  session.getBasicRemote().sendText(message);
}

Once again, just recompile the changed files, hit refresh in the browser and JRebel reloads the EchoEndpoint:

2014-11-25 00:09:05 JRebel: Reloading class 'demo.EchoEndpoint'.
...
2014-11-25 00:09:05 JRebel-Spring: Reconfiguring bean 'echoEndpoint' [demo.EchoEndpoint]

Now we’ve constructed a high performance parrot, echoing everything back through that full duplex WebSocket. Pretty sweet right, but if you’d like to know more about Spring Boot and JRebel you can rewatch our Spring Boot and JRebel webinar with Pivotal.


SET UP JREBEL IN THE NEXT 10 MIN!