Spring 5 and Servlet 4 – The PushBuilder

1. Introduction

The Server Push technology — part of HTTP/2 (RFC 7540) — allows us to send resources to the client proactively from the server-side. This is a major change from HTTP/1.X pull-based approach.

One of the new features that Spring 5 brings – is the server push support that comes with Jakarta EE 8 Servlet 4.0 API. In this article, we’ll explore how to use server push and integrate it with Spring MVC controllers.

2. Maven Dependency

Let’s start by defining dependencies we’re going to use:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.8.RELEASE</version>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.0</version>
    <scope>provided</scope>
</dependency>

The most recent versions of spring-mvc and servlet-api can be found on Maven Central.

3. HTTP/2 Requirements

To use server push, we’ll need to run our application in a container that supports HTTP/2 and the Servlet 4.0 API. Configuration requirements of various containers can be found here, in the Spring wiki.

Additionally, we’ll need HTTP/2 support on the client-side; of course, most current browsers do have this support.

4. PushBuilder Features

The PushBuilder interface is responsible for implementing server push. In Spring MVC, we can inject a PushBuilder as an argument of the methods annotated with @RequestMapping.

At this point, it’s important to consider that – if the client doesn’t have HTTP/2 support – the reference will be sent as null.

Here is the core API offered by the PushBuilder interface:

  • path (String path) – indicates the resource that we’re going to send
  • push() – sends the resource to the client
  • addHeader (String name, String value) – indicates the header that we’ll use for the pushed resource

5. Quick Example

To demonstrate the integration, we’ll create the demo.jsp page with one resource — logo.png:

<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>PushBuilder demo</title>
</head>
<body>
    <span>PushBuilder demo</span>
    <br>
    <img src="<c:url value="/resources/logo.png"/>" alt="Logo" 
      height="126" width="411">
    <br>
    <!--Content-->
</body>
</html>

We’ll also expose two endpoints with the PushController controller — one that uses server push and another that doesn’t:

@Controller
public class PushController {

    @GetMapping(path = "/demoWithPush")
    public String demoWithPush(PushBuilder pushBuilder) {
        if (null != pushBuilder) {
            pushBuilder.path("resources/logo.png").push();
        }
        return "demo";
    }

    @GetMapping(path = "/demoWithoutPush")
    public String demoWithoutPush() {
        return "demo";
    }
}

Using the Chrome Development tools, we can see the differences by calling both endpoints.

When we call the demoWithoutPush method, the view and the resource is published and consumed by the client using the pull technology:


When we call the demoWithPush method, we can see the use of the push server and how the resource is delivered in advance by the server, resulting in a lower load time:


The server push technology can improve the load time of the pages of our applications in many scenarios. That being said, we do need to consider that, although we decrease the latency, we can increase the bandwidth – depending on the number of resources we serve.

It’s also a good idea to combine this technology with other strategies such as Caching, Resource Minification, and CDN, and to run performance tests on our application to determine the ideal endpoints for using server push.

6. Conclusion

In this quick tutorial, we saw an example of how to use the server push technology with Spring MVC using the PushBuilder interface, and we compared the load times when using it versus the standard pull technology.

As always, the source code is available over on GitHub.

Related posts:

Exploring the Spring 5 WebFlux URL Matching
Introduction to PCollections
Functional Interfaces in Java 8
Getting Started with Stream Processing with Spring Cloud Data Flow
Exploring the Spring Boot TestRestTemplate
Java Program to Implement Threaded Binary Tree
Tìm hiểu về xác thực và phân quyền trong ứng dụng
Date Time trong Java 8
Java Program to Implement Attribute API
The Difference Between map() and flatMap()
Spring Boot - Tracing Micro Service Logs
Guide to Dynamic Tests in Junit 5
Cơ chế Upcasting và Downcasting trong java
Guide to the Synchronized Keyword in Java
Java Program to Print only Odd Numbered Levels of a Tree
Guide to PriorityBlockingQueue in Java
Java Program to Implement Horner Algorithm
Java Program to Implement Johnson’s Algorithm
Java Program to Find Minimum Element in an Array using Linear Search
Java Program to Solve a Matching Problem for a Given Specific Case
Java Program to Implement the Checksum Method for Small String Messages and Detect
Java Program to Use Dynamic Programming to Solve Approximate String Matching
An Introduction to Java.util.Hashtable Class
Java Program to Implement Gale Shapley Algorithm
Spring MVC and the @ModelAttribute Annotation
A Guide to JUnit 5
Java Program to Perform Partition of an Integer in All Possible Ways
Servlet 3 Async Support with Spring MVC and Spring Security
Binary Numbers in Java
Guide to java.util.concurrent.Future
Generating Random Numbers in a Range in Java
“Stream has already been operated upon or closed” Exception in Java