The New Age for Spring - Spring Framework 6.0, Spring Boot 3.0 and lack of support for pre-JDK 17 - JVM Weekly #23
Today, the topic of the edition could only be one - Spring. But since a lot (A LOT) has happened lately with the most popular JVM framework, I decided to devote an entire edition to it. Enjoy!
Contrary to popular belief, the Java world has been quite dynamic in recent years. There are a fair number of new initiatives, frameworks or changes in standards - enough to rationalize the appearance of a weekly review. It is true, however, that while this proportion has been changing somewhat in recent years, Spring continues to divide and rule in this world - and we're talking about both older projects and new initiatives. Therefore, while we can rejoice in how other frameworks or libraries are pushing the ecosystem forward, the wider adoption of standards like GraalVM or JPMS already depends on the King. And since the last few weeks have seen a slew of major announcements from Spring, we'll devote today's edition to it. We'll look at the release of Spring Framework 6.0 and Spring Boot 3.0, their repercussions, as well as the initiatives accompanying them, because there are a lot of those.
Who will be able to actually use the new Spring?
Over the past week, new versions of both major projects from under the Spring umbrella - Spring Framework 6.0 and Spring Boot 3.0 - have been released. And no matter how many changes they bring in themselves, surely the biggest revolution is the dropping of support for older versions of Java. And when I say "older" here, I mean not Java 1.6, not Java 1.8 but even... Java 16. The new Spring requires Java 17 in order to function. Its creators have made no compromises here and have made the new "major" version work exclusively with the latest LTS release available at the moment.
How many projects in theory will be able to switch to the new Spring? Let's look at Java usage statistics. The most recent report describing the Java ecosystem, the April 2022 New Relic 2022 State of the Java Ecosystem Report showed Java 17 usage at 0.37%. However, this data must be viewed in context. After all, the previous LTS, JDK 11, overtook the reigning JDK 1.8 for years in the report and reached almost 50% market saturation. This means that the migration process is doing as well as it can, and since moving from JDK 11 to JDK 17 is a really simple matter (especially compared to getting to JDK 11, as LinkedIn once snagely described), the only thing standing in the way is giving potential users an argument to add such a task to their next iteration.
The main course: Spring Framework 6.0
It wouldn't be this text (and many of the releases described here) if Spring Framework 6.0 - the new release, being the beating heart of the Spring ecosystem - hadn't had its premiere on the 17th of November. For years it's been the one to make headlines; however, in recent years it's been somewhat overshadowed by Spring Boot, which, along with the popularity of Microservices, has become Spring's flagship release. But don't let the apparent retreat into the shadows fool you - the Spring Framework is the part where the most interesting changes from an engineering point of view usually happen. We'll walk through the most spectacular ones:
Bye bye Java EE, hello Jakarta EE!
New Java is one thing, but Spring Framework 6.0 also brings support for Jakarta EE 9.1+. This is worth knowing, because the migration process here may prove (which will probably come as a surprise to many) more difficult than with Java. After all, let me remind you that Jakarta EE 9.1+ is the edition that got rid of the javax.*
package in favor of jakarta.*
, thus escaping the reach of Oracle and the trademarks they own. For Spring, this is a huge leap, as it will enable compatibility with subsequent versions of Jakarta EE, which are bringing more value to the ecosystem. The developers themselves advise that it's best to switch right away to the recently released 10 - as this one brings the improvements of several important standards.
Depending on how much your application depended on Java EE and its associated libraries, the more difficult the migration will be. Unless you use tools from JetBrains - then it should be a lot easier.
Ahead-of-Time compilation or JPMS - choose one
If you've been following the news about the new Spring since its first announcements, I have some bad news for you: it won't, be as rich a release as promised. It turns out that the long-awaited support for JPMS, the Java module system, is not ready for day zero. As the developers promise, it can be expected to appear in later versions, but the first version of Spring Framework 6 focuses specifically on support for Ahead-of-Time and GraalVM compilation, and modules would hinder this process by complicating the so-called "reachability analysis." After all, it should be remembered that unlike new players in the framework market like Quarkus, Helidon and Micronaut, Spring relies very, very heavily on the Reflection API. For him, therefore, the process of supporting GraalVM, which does not support reflection, is much more difficult.
Hence the modules have gone down the drain. The developers make it clear that they are counting on Project Leyden here - one meant to standardize AoT compilation on the JVM. Since this will be part of the JDK, it must take JPMS into account, which should make the work of third-party developers easier in this aspect. For now, however, Spring chooses to support Native Images. And if you want to learn more about the support of Native Images itself and what it translates into in the Spring context, I refer you to the presentations Ahead Of Time and Native in Spring Boot 3.0 by Stéphane Nicoll and Brian Clozel. Still, we'll return to the topic of AoT in a moment, when describing what's new in Spring Boot 3.0
It seems to me that the whole situation is strongly symptomatic of everything that's going on with JPMS - even the Framework, which could theoretically introduce modularization more easily than Spring, isn't exactly flocking to it. At this point, modules seem to serve mainly JDK developers, and in this form, they work great, as they allow incremental development of the entire platform.
Some changes under-the-hood.
For the sake of completeness, I can't help but mention here two interesting changes under the hood. One of the things that Spring developers are looking at is the development of virtual threads. At the beginning of October, the quite an extensive publication appeared, being probably Spring's first official position on this issue. Once again, the framework's long heritage casts a shadow here - the framework has large numbers of synchronized blocks, which, while not a blocker per se, makes the whole process a bit more complicated. However, developers are aware of this and are analyzing which parts they need to address first and experimenting with the JDK-provided methods, and in fact, the first refactorings have already made their way into the released Spring Framework 6.0. As a community, this approach should please us. It's nice that Spring cares about realistically gaining something from these virtual threads, and not just ticking off another "revolutionary" feature for itself.
The last thing in the context of Spring Framework 6.0 that I would like to mention is the redesign of Project CRaC. It may allow eliminating one of Spring's biggest and most frequently mentioned drawbacks - its long startup time. For now, the functionality (even in Preview) is not yet ready for extensive testing, but the sneak peek we can already see in the presentation Java on CRaC: Superfast JVM Application Startup, given by Simon Ritter at Devoxx Belgium whets the appetite.
What you will realistically use - Spring Boot 3.0
As I mentioned, I assume that a good number of you will be using this very Spring distribution. Therefore, even though we have already hooked on the topic of AoT it is with Spring Boot that we will consider what it really comes down to in practice. That's why you need to dust off the old announcements and take a look at the long-going project, called Spring-Native.
Ahead-of-Time compilation is really nothing more than compiling the source code to the final version not through an intermediate step (bytecode and then a just-in-time compiler), but at the very start of the process. This approach makes it possible to optimize and generate machine code in advance, while getting rid of all the JVM fat, like Classpath or the virtual machine itself. As a result, applications start faster, they also devour fewer resources - this is due to the fact that there are simply fewer unnecessary blocks in the running process.
However, it's not for free - applications compiled by Graal VM (because it's the AoT compiler we've been talking about all along) must work under the "closed world assumption". It means that all bytecode in the application that can be called at runtime must be known (observed and analyzed) already at build time. This particularly strongly affects programs that use the reflection mechanism. This is because the compiler has to guess what (usually dynamic) resources it should add to the final artifact, even though there are no direct references to them in the code. Spring, as everyone is aware - is very much based on reflection, so the work to adapt it precisely to work with GraalVM was packaged into an R&D project called Spring-Native, which has been in development for almost three years. Now it is finally becoming part of Spring, and Spring Boot will benefit the most.
If you want to learn more about how GraalVM works, I invite you to article written in the context of the Spring Framework, introduction by Josh Long, but also the official Oracle text on native images.
What's beyond Spring-Native? One of my favorite additions to Spring Boot is the improved support for Micrometer. I've been watching the development of this library for some time now, and I'm sure that a new standard that will stay with us for years is just being born before our eyes. This is manifested if only by the fact that more and more tools are providing attempts to support it as conveniently as possible. Just as Quarkus abandoned for Micrometer solutions derived from Jakarta EE, so now Spring Boot 3.0 also emphasizes as much compatibility as possible. For example, Spring Cloud Sleuth is replaced by the Micrometer Tracing framework in the new version. If you are curious about what new features await Spring Boot 3.0 users in this aspect, I invite you to the article Observability with Spring Boot 3.
These, of course, are not all the novelties - a considerable remodeling has undergone min. model of application properties. the most important ones you will find in the official Release Notes.
Associated projects
To understand what a big change the Spring Framework 6.0 fixes have been - the Ahead-of-Time compilation, the migration to Jakarta EE 10, and the addition of Micrometer support - one only has to look at the release notes of most of the companion projects. Indeed, these are dominated by reporting on compatibility with the latest version of the project, with at most minor fixes poking through from underneath - it shows how much work the entire community was required to take a big step forward.
Such a Spring Web Service 4.0, for example, boasts (aside from the above upgrades) nothing but a move to GitHub when it comes to tracking releases. Spring Security 6.0 also introduces rather minor additions. Things are a bit more interesting with Spring GraphQL 1.1.0, Spring Data 2022.0 or the new Spring for Apache Kafka 3.0 and Spring for RabbitMQ 3.0 - these include some new APIs. However, even in their case, the penny of announcements is information about a successful migration, even if Spring Data can be considered a knockout case of a project that has realistically informed what all this AoT compilation entails for them.
Microservices are starting to be passe - Spring Modulith
When describing Spring Boot 3.0, I mentioned that this is the version that will probably be the target release for most Spring users (or at least those who are considering migrating to its new update at all). Spring Boot is, after all, a release dedicated to such Cloud Native applications or Microservices in general. In recent years (or even in the last decade), it was Microservices that was the architectural pattern that became this "modern" way of developing applications, to the level when it can be considered a kind of cargo cult, also in the Java world. We have struggled for so long to make our frameworks suitable for this type of architecture that we now treat it as the default solution.
However, there is a growing call in the community for a return to the monolith, but somewhat reinvented. Proponents of this approach urge that with today's tools and good modularization, we can create a codebase that has a fair amount of the advantages of microservices with surprisingly few of its disadvantages. I refer those interested to the Majestic Monolith concept by DHH, as well as the interesting Modular Monolith: A Primer series.
All right, but how does this relate to the topic of Spring? Well, along with Spring Boot, the Spring Modulith version 0.1 project premiered, which is expected to bring Spring into the era of the majestic monolith. Spring-Modulith is an extension of the existing Moduliths project (which it will replace), but even better integrated with Spring itself. The very way the whole thing works is very interesting - instead of interfering heavily with the build process, it uses integration tests to verify the project. These use ArchUnit - a library whose purpose is precisely to verify dependencies between modules. The magic of Modulith, however, is that thanks to its familiar runtime environment (Spring Boot 3.0 applications) it is able to preconfigure ArchUnit - which it does. This makes it easy for us to test whether some architectural spaghetti has slipped through Code Review.
Since, as we wrote above, Spring has withdrawn (for now) from JPMS support, Modulith seems to be a simple, useful alternative. If we add to this the fact that the project is able to automatically generate architectural diagrams from live code, the project is worth getting interested in. To that end, I'm tossing in two additional resources - an interview with the project's creator, Oliver Drotbohm, from InfoQ, and a tutorial from Nicolas Fränkel.
For the very end - how to migrate your projects?
Well, we've talked about the changes that the new Spring (treating it as a whole) will bring, and hopefully, despite some work to be done, I've managed to encourage you to give it a try. However, it is known that it is best to go into such an adventure prepared.
Spring developers back in May dropped some suggestions on how to adapt your code for Spring Boot 3.0, and if you've actually done that (bumped up Java, Jakarta, migrated Properties, removed deprecated code) then you're basically ready to start playing with the whole thing right away. However, if in addition to simply bumping up the dependency versions, you still want to make the most of the framework's (and Java's) new capabilities, be sure to take a look at the article The best way to do the Spring 6 migration by Vlad Mihalcea. In it, you will read how to get the most value out of the whole process.
Is Spring a better chkice than. NET?
dev time and performances vise