21

What’s new in Spring Boot 2.3 (Java 14, OCI images, etc.)

 3 years ago
source link: https://rieckpil.de/whats-new-in-spring-boot-2-3/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Spring Boot 2.3 release

Java 14 support in Spring Boot 2.3

One of the central updates coming with Spring Boot 2.3 is the official support of Java 14. We can now create Spring Boot applications using the latest Java version and use its preview features to provide feedback about them:

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
 
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.0.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
 
  <groupId>de.rieckpil.blog</groupId>
  <artifactId>whats-new-in-spring-boot-2-3</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>whats-new-in-spring-boot-2-3</name>
  <description>Updates with Spring Boot 2.3</description>
 
  <properties>
    <java.version>14</java.version>
  </properties>
 
  <dependencies>
    <!-- classic Spring Boot Starters, e.g. web, test, ... -->
  </dependencies>
 
  <build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <jvmArguments>
            --enable-preview
          </jvmArguments>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <compilerArgs>
            --enable-preview
          </compilerArgs>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <argLine>
            --enable-preview
          </argLine>
        </configuration>
      </plugin>
    </plugins>
  </build>
 
</project>

With this setup, let’s create our first Java 14 Record :

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public record User(String name, LocalDate dateOfBirth, boolean isRegistered) {
}

… and use it as a plain data object for one of our endpoints:

@GetMapping("/users")
public List<User> getUsers() {
  return List.of(new User("Duke", LocalDate.now(), true),
  new User("Duke", LocalDate.now().minusDays(1), false));
}

For a complete list of all new Java 14 features, take a look at this list .

Besides Java 14, Spring Boot 2.3 still supports Java 8 and 11.

Building OCI images and layered .jar files

One great new feature when it comes to deploying Spring Boot applications is to create layered .jar files. As most of the Spring Boot applications are deployed inside a Docker container, you have to create a new Docker image on every code change. With the traditional approach of copying the fat jar to an existing Docker base image (e.g. openjdk-11 ), you always have to copy the whole build artifact e.g. 10 – 50 MB .jar file over and over again.

This is suboptimal as usually only some Java classes change whereas your dependencies change not that frequently. A better approach would be to only copy the application code (usually some KBs) and reuse existing layers of your Docker image (containing all your dependencies) to speed up subsequent Docker image builds.

With Spring Boot 2.3 you can now configure the Spring Boot plugin (works for Maven and Gradle) to create a .jar file with the following layers:

  • dependencies (includes regularly released dependencies)
  • spring-boot-loader (for everything under org/springframework/boot/loader )
  • snapshot-dependencies (for snapshot dependencies)
  • application (includes application classes and resources)
<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
    <layers>
      <enabled>true</enabled>
    </layers>
  </configuration>
</plugin>

During your daily development most probably will only the application layer change.

We can demonstrate this feature by showcasing another new feature of Spring Boot 2.3: Building OCI (Open Container Initiative) images using Cloud Native Buildpacks . By default, the Spring Boot plugin uses one of Paketo’s Buildpacks and we can build this image while executing a specific Maven Goal:

<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
    <jvmArguments>
      --enable-preview
    </jvmArguments>
    <layers>
      <enabled>true</enabled>
    </layers>
    <image>
      <name>myregistry.com/rieckpil/${project.artifactId}</name>
      <env>
        <BP_JVM_VERSION>14.0.1</BP_JVM_VERSION>
      </env>
    </image>
  </configuration>
  <executions>
    <execution>
      <goals>
        <goal>build-image</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Once we now execute mvn package , we’ll get a ready to use Docker image. While building the image, the Builder of the Buildpack is able to detect our layered .jar file and can reuse existing layers that did not change (e.g. our dependencies).

If you build your Spring Boot application and change the implementation of a class afterward and rebuild the image, you’ll see that only the last Docker layer changed:

mvn package
docker history myregistry.com/rieckpil/whats-new-in-spring-boot-2-3:latest
IMAGE               CREATED             CREATED BY          SIZE                COMMENT
4a38d5b029c1        40 years ago                            12kB  
<missing>           40 years ago                            0B                  
<missing>           40 years ago                            10.8kB              
<missing>           40 years ago                            0B                  
<missing>           40 years ago                            224kB              
<missing>           40 years ago                            18MB  
// ...
 
// do changes to the source code
mvn package
docker history myregistry.com/rieckpil/whats-new-in-spring-boot-2-3:latest
IMAGE               CREATED             CREATED BY          SIZE                COMMENT
7a92643ab146        40 years ago                            12kB                
<missing>           40 years ago                            0B                  
<missing>           40 years ago                            10.8kB              
<missing>           40 years ago                            0B                  
<missing>           40 years ago                            224kB              
<missing>           40 years ago                            18MB

Read more about these two features in the Spring Boot documentation .

Spring Boot Starter for Validation

Both spring-boot-starter-web and spring-boot-starter-webflux don’t contain the spring-boot-start-validation anymore. If you are relying on Bean Validation (now called Jakarta Bean Validation) e.g. at your controller level:

@GetMapping("/messages")
public List<String> getMessages(@RequestParam("size") @Positive @Max(6) Integer size) {
  return List.of("Hello", "World", "Foo", "Bar", "Duke", "Spring")
    .stream()
    .limit(size)
    .collect(Collectors.toList());
}

You have to manually add the starter for validation to your project:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

You can read about the reason for this change in the corresponding GitHub issue .

Binding error messages for the Whitelabel error page

If you already work with Spring Boot for some time, you might have seen the Whitelabel error page during development. This error page usually appears in your browser whenever there is an exception in your service that you don’t handle gracefully (e.g. with @ExceptionHandler ) or happens inside the Spring Framework (e.g. Spring MVC can’t find a view).

Before Spring Boot 2.3 this page contains the error message and error bindings by default. With this behavior, you’ll leak internal information about the exception to the user which might contain sensitive data. Let’s consider the following trivial example:

@GetMapping("/api/customers")
public Integer api() {
  if (2 % 2 == 0) {
    throw new RuntimeException("Exception happened and customer Duke only has 42 $ left");
  }
  return 40 + 2;
}

When we access this endpoint with a Spring Boot < 2.3, we’ll get the following output:

whiteLabelErrorPageSpringBootBefore2.3.png

In such cases, you might not want to include the error message as it leaks critical information . With Spring Boot 2.3 the Whitelabel error page does not contain any error message by default anymore:

whiteLabelErrorPageSpringBootWith2.3.png

You can still configure your application to include the error message (e.g. for debugging):

server.error.include-message=always
server.error.include-binding-errors=always

Configuration property deprecations and renamings

With the release of Spring Boot 2.3 some configurations properties are renamed or now deprecated. The Spring Boot team provides support to migrate such properties using  a dependency:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-properties-migrator</artifactId>
  <scope>runtime</scope>
</dependency>

If your project contains property definitions that are no longer valid, the dependency above will take care of temporarily migrating and printing them during application startup.

As an example, I’ll use the following deprecated properties to configure the thread pool size for Tomcat:

server.tomcat.max-threads=42
server.tomcat.min-spare-threads=10

Once we now start the application, we’ll get a log output which also includes how the old property is temporarily replaced:

WARN 32699 --- [main] PropertiesMigrationListener  :
The use of configuration keys that have been renamed was found in the environment:
 
Property source 'applicationConfig: [classpath:/application.properties]':
 Key: server.tomcat.max-threads
 Line: 1
 Replacement: server.tomcat.threads.max
 Key: server.tomcat.min-spare-threads
 Line: 2
 Replacement: server.tomcat.threads.min-spare

You can then use the Replacement hint in the log message and rename all your configuration properties. Once the PropertiesMigrationListener doesn’t warn about any depreciation, you can get rid of the dependency.

Further dependency upgrades with Spring Boot 2.3

Besides other dependency upgrades, theses are one of the most important ones:

  • Spring Data Neumann : Repository support for Kotlin coroutines, upgrades for MongoDB, ElasticSearch, Couchbase and more
  • Spring Security 5.3 : OAuth 2 client & resource server updates, enhancing the documentation and more
  • Flyway 6.4
  • JUnit Jupiter 5.6 : find release notes here
  • Kotlin 1.3.72
  • etc.

If you are curious about what changed with previous versions of Spring Boot, take a look at my review ofSpring Boot 2.1 and2.2.

While this blog post contains the most important changes from my point of view,  there is more to explore in the official release notes . You can find this Spring Boot 2.3 showcase application on GitHub.

Have fun using Spring Boot 2.3.

Phil


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK