Spring Boot 3: a Path to Native Applications

Introduction

Spring Boot has become one of the most popular Java frameworks for building modern, scalable, and robust web applications. With its latest release, Spring Boot 3 has introduced several groundbreaking features that are set to change the game for developers. In this article, we will take a closer look at the support for native images and explore how they can help you take your Spring Boot applications to the next level. So, let’s dive in and explore what’s new in Spring Boot 3!

GraalVM – The Way to Native

GraalVM is an open-source virtual machine that was designed to support multiple programming languages and execution modes. It was born out of the need to improve the performance and flexibility of JVM (Java Virtual Machine) based applications.

The purpose of GraalVM is to provide a unified platform for running various programming languages and execution modes, including Java, JavaScript, Ruby, Python, and other languages. It aims to increase performance and reduce resource consumption by leveraging advanced compiler and runtime techniques. 

GraalVM also provides a number of other features such as ahead-of-time (AOT) compilation, just-in-time (JIT) compilation, and native image generation, which further improves application performance, security, and start-up time. 

Overall, GraalVM was born to address the limitations of traditional JVM-based applications and provide a more efficient and flexible platform for building modern applications.

With the advent of GraalVM and its native capabilities, there is an increasing interest in developing native applications, as they offer significant advantages over traditional JVM-based applications, such as faster start-up times, lower memory consumption, and smaller executable sizes. Spring Boot 3 embraces this trend by providing support for native applications through the new project, Spring Native.

Introducing Spring Native

Spring Native is an innovative project within the Spring Framework ecosystem that aims to provide support for compiling Spring applications to native executables using the GraalVM Native Image compiler. This enables developers to create lightweight, high-performance executables that start up faster, consume fewer resources, and offer better performance compared to traditional Java applications running on a JVM (Java Virtual Machine).

Spring Native enhances the developer experience in creating native applications by extending the Spring framework with native configuration and optimisations, making it easier to create native executables that work seamlessly with the vast Spring ecosystem.

Creating a native application is as easy as using the maven or gradle plugin during compilation:

./mvnw package -Pative

./gradlew nativeCompile

Main features of Spring Native for Java applications:

Fast startup timeAs native executables, Spring Boot applications exhibit significantly faster start-up times compared to traditional JVM-based applications. This makes them well-suited for serverless, microservices, and other scenarios where quick start-up times are crucial.
Reduced memory footprintNative applications generally have a smaller memory footprint, which helps in reducing resource consumption and operational costs, especially in containerised and cloud-based environments.
Ahead-of-Time compilationSpring Native leverages the GraalVM Native Image compiler to perform AOT compilation, which translates Java bytecode to native machine code during the build process. This results in faster start-up times and better runtime performance, as the application doesn’t rely on Just-In-Time (JIT) compilation at runtime.
Seamless integration with Spring ecosystemSpring Native is designed to work with the extensive Spring ecosystem, including Spring Boot, Spring Data, Spring Security, and more. Developers can continue using familiar Spring APIs and annotations to build native applications.
Automatic configurationSpring Native automatically generates the necessary configuration metadata (known as reachability metadata) required by GraalVM Native Image during the build process. This simplifies the process of creating native applications and reduces the manual effort involved in maintaining configuration files.
GraalVM supportSpring Native is specifically designed to work with GraalVM. This ensures that developers can leverage the full capabilities of GraalVM when building native applications with Spring Native.

In summary, Spring Native is an exciting project that enhances the capabilities of the Spring Framework by enabling developers to create native applications with better performance, faster start-up times, and reduced resource consumption. Its seamless integration with the Spring ecosystem and automatic configuration support make it a promising solution for developing high-performance Java applications in the era of cloud-native and container-based deployments.

What happens during the native compilation?

When we build a native image, the compiler performs a static analysis and only the elements that are reached from our application entry-point are included. These elements basically consist in the code that our application needs to work, such as JDK classes, dependencies or our own code.

Some elements such as classes or methods may not be discovered due to some aspects such as reflection, dynamic proxies and serialisation. Although, the executable will be created correctly, if an element is not included it could lead to runtime failures, so we need to manually tell the compiler that they should also be taken into account and included in the final artefact.

Reachability metadata

In Spring Boot 3, the way we tell the compiler to take into account certain elements during the process of creating a native image is by using reachability metadata.

  • These metadata consists in files that register the classes that we want to include in the native image. These files must be stored under META-INF.native-image and have specific naming conventions:
  • reflect-config.json -> Includes all relative to source code that need to be included
  • resource-config.json -> Includes all relative to resources that need to be included

Registering all those elements necessary for the native image to work properly can be a tedious and time-consuming process, especially if your application is large and uses a lot of external third-party dependencies. To assist developers during the process, there is a common Github repository which includes a base configuration for reachability metadata. This repository is consulted during the creation of the native image and for example, if the compiler detects that our app uses PostgreSQL, the reachability metadata related to this will be downloaded from the repository.

Is native the future of Software Development?

We have gone through the main features provided by native applications. However, whether they are the future of software development is still up for debate, as it has its pros and cons that need to be considered:

Reduced memory footprintLess memory consumption compared to their JVM counterparts, which can be particularly beneficial for cloud deployments and resource-constrained environments.
Cross-language interoperabilityGraalVM supports multiple programming languages, including Java, JavaScript, Ruby, R, and Python. This allows developers to build polyglot applications and leverage the best features and libraries of each language.
Platform independenceNative applications built with GraalVM can run on different platforms without the need for a JVM, which simplifies deployment and can reduce the size of the application.
Incredible fast start timeStart time in milliseconds is an impressive metric, especially if we talk about Spring Boot applications. This will for instance make horizontal scalability much more interesting as we can have a second instance of our app running in a blink.
Longer build timesCreating native applications with GraalVM can take longer compared to traditional Java applications, as the Ahead-of-Time (AOT) compilation process is more time-consuming.
Limited reflection and dynamic featuresGraalVM native applications have limitations in terms of reflection and dynamic features, which can be a drawback for some applications that rely on these capabilities.
Compatibility issuesNot all Java libraries and frameworks are compatible with GraalVM native images, which might require developers to make adjustments or find alternatives.
Increased complexityBuilding native applications with GraalVM can introduce additional complexity in terms of configuration, debugging, and deployment, especially for developers who are used to working with the JVM.

In conclusion, GraalVM offers some significant advantages over traditional JVMs, such as improved performance and reduced memory footprint. However, it also has some drawbacks, such as longer build times and compatibility issues. Whether GraalVM becomes the future of software development will largely depend on how well it addresses these challenges and continues to evolve in response to developers’ needs, but the fact that it is now natively supported in Spring Boot 3 is a great help!