BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles Java Champion Josh Long on Spring Framework 6 and Spring Boot 3

Java Champion Josh Long on Spring Framework 6 and Spring Boot 3

Key Takeaways

  • Microservices are an opportunity to show where Java lags behind other languages.
  • Reactive programming provides a concise DSL to express the movement of state and to write concurrent, multithreaded code with better scaling.
  • Developing in Spring Boot works well even without special tooling support.
  • Regarding current Java developments, Josh Long is most excited about Virtual Threads in Project Loom, Java optimization in Project Leyden, and Foreign-Function access in Project Panama.
  • Josh Long wishes for real lambdas in Java — structural lambdas — and would like to revive Spring Rich, a defunct framework for building desktop Swing-powered client applications.

VMware released Spring Framework 6 and Spring Boot 3. After five years of Spring Framework 5, these releases start a new generation for the Spring ecosystem. Spring Framework 6 requires Java 17 and Jakarta EE 9 and is compatible with the recently released Jakarta EE 10. It also embeds observability through Micrometer with tracing and metrics. Spring Boot 3 requires Spring Framework 6. It has built-in support for creating native executables through static Ahead-of-Time (AOT) compilation with GraalVM Native Image. Further details on these two releases may be found in this InfoQ news story.

InfoQ spoke with Josh Long, Java Champion and first Spring Developer Advocate at VMware, about these two releases. Juergen Hoeller, Spring Framework project lead at VMware, contributed to one answer.

InfoQ: As a Spring Developer Advocate, you give talks, write code, publish articles and books, and have a podcast. What does a typical day for Josh Long look like?

Josh Long: It's hard to say! My work finds me talking to all sorts of people, both in person and online, so I never know where I'll be or what work I'll focus on. Usually, though, the goal is to advance the will of the ecosystem. So that means learning about their use cases and advancing solutions to their problems. If that means talking to the Spring team and/or sending a pull request, I'll happily do that. If it means giving a presentation, recording a podcast, writing an article or a book or producing a video, then I'll do that.

InfoQ: VMware gets feedback about Spring from many sources: conferences, user groups, issue trackers, Stack Overflow, Slack, Reddit, Twitter, and so on. But happy users typically stay silent, and the loudest complainers may not voice essential issues. So, how does VMware collect and prioritize user feedback?

Long: This is a very good question: everything lands in GitHub, eventually. We pay special attention to StackOverflow tags and do our best to respond to them, but if a bug is discovered there, it ultimately lands in GitHub. GitHub is a great way to impact the projects. We try to make it easy, like having labels for newcomers who want to contribute to start somewhere where we could mentor them. GitHub, of course, is not a great place for questions and answers — use Stackoverflow for that. Our focus on GitHub is so great that even within the teams themselves, we send pull requests to our own projects and use that workflow.

InfoQ: There are many projects under the Spring umbrella. VMware has to educate Spring users about all of them. How does VMware know what Spring users don’t know so it can teach them?

Long: In two words: we don't. We can surmise, of course. We spend a lot of effort advancing the new, novel, the latest and greatest. But we also are constantly renewing the fundamental introductory content. You wouldn't believe how many times I've redone the "first steps in..." for a particular project :) We're also acutely aware that while people landing on our portals and properties on the internet might be invested long-time users, people finding Spring through other means may know less. So are constantly putting out the "your first steps in..." introductory content. And anyway, sometimes "the first steps in…" changes enough that the fundamentals become new and novel :) 

InfoQ: Java legacy applications often use older versions of Java and frameworks. Microservices allow developers to put new technology stacks into production at a lower risk. Do you see this more as an opportunity for Java to showcase new features and releases? Or is it more of a threat because developers can test-drive Java competitors like .NET, Go, JavaScript or Python?

Long: Threat? Quite the contrary: if Java reflects poorly when viewed through the prism of other languages, then it's better for that to be apparent and to act as a forcing function to propel Java forward. And, let's be honest: Java can't be the best at everything. Microservices mean we can choose to use Spring and Java for all the use cases that make sense — without feeling trapped in case Java and Spring don't offer the most compelling solution. Don't ask me what that use case is because I have no idea…

InfoQ: Spring 5 added explicit Spring support for Kotlin. In your estimate, what percentage of Spring development happens in Kotlin these days?

Long: I don't know. But it's the second most widely used language on the Spring Initializr.

InfoQ: Scala never got such explicit support in Spring. Why do you think that is?

Long: It did! We had a project called Spring Scala way back in 2012.  We really wanted it to work. Before we announced Spring Scala, we even had a Spring Integration DSL in Scala. We tried. It just seems like there wasn't a community that wanted it to work. Which is a pity. These days, with reactive and functional programming so front-and-center, I feel like the Java and Scala communities have more in common than ever.

InfoQ: Spring 5 also added reactive applications. Now you’re a proponent of reactive applications and even wrote a book about it. What makes reactive applications so attractive to you?

Long: I love reactive programming. It gives me three significant benefits:

  • A concise DSL in which to express the movement of state in a system — in a way that robustly addresses the volatile nature of systems through things like backpressure, timeouts, retries, etc. This concise DSL simplifies building systems, as you end up with one abstraction for all your use cases.
  • A concise DSL in which to write concurrent, multithreaded code — free of so much of the fraught threading and state-management logic that bedevils concurrent code.
  • An elegant way to write code in such a way that the runtime can better use threads to scale (i.e., handle more requests per second).

InfoQ: For which problems or applications is reactive development a perfect fit?

Long: If reactive abstractions are suitable to your domain and you want to learn something new, reactive programming is a good fit for all workloads. Why wouldn't you want more scalable, safer (more robust), and more consistent code?

InfoQ:  Where is reactive development not a good fit?

Long: Reactive development requires a bit of a paradigm change when writing code. It's not a drop-in replacement or a switch you can just turn on to get some scalability like Project Loom will be. If you're not interested in learning this new paradigm, and you're OK to do without the benefits only reactive programming can offer, then it makes no sense to embrace it.

InfoQ: Common complaints about reactive development are an increased cognitive load and more difficult debugging. How valid are these complaints in Spring Framework 6 and Spring Boot 3?

Long: I don't know that we're doing all that much to address these concerns directly in Spring Boot 3. The usual mechanisms still work, though! Users can put breakpoints in parts of a reactive pipeline. They can use the Reactor Tools project to capture a sort of composite stack trace from all threads in a pipeline. They can use the .log() and .tap() operators to get information about data movement through the pipeline, etc. Spring Boot 3 offers one notable improvement: Spring now supports capturing both metrics and trace information through the Micrometer Metrics and Micrometer Tracing projects. Reactor even has new capabilities to support the new Micrometer Observation abstraction in reactive pipelines.

InfoQ: How important is tool support (such as IDEs and build tools) for the success of a framework? At least experienced users often bypass wizards and utilities and edit configuration files and code directly.

Long: This is a fascinating question. I have worked really hard to make the case that tooling is not very important to the experience of the Spring Boot developer. Indeed, since Spring Boot's debut, we've supported writing new applications with any barebones Java IDE. You don't need the IntelliJ IDEA Ultimate Edition, specialized support for Spring XML namespaces, or even the Java EE and WTP support in Eclipse to work with Spring Boot. If your tool supports public static void main, Apache Maven or Gradle, and the version of Java required, then you're all set! 

And there are some places where Spring Boot got things that might benefit from tooling, like ye ole application.properties and application.yaml. But even here, you don't need tooling: Spring Boot provides the Spring Boot Actuator module, which gives you an enumeration of all the properties you might use in those files.

That said: it doesn't hurt when everything's literally at your fingertips. Good tooling can feel like it's whole keystrokes ahead of you. Who doesn't love that? To that end, we've done a lot of work to make the experience for Eclipse and VS Code (and, by extension, most tools that support the Eclipse Java Language Server) developers as pleasant as possible. 

I think good tooling is even more important as it becomes necessary to migrate existing code. A good case in point is the new Jakarta EE APIs. Jakarta EE supersedes what was Java EE: All javax.*  types have been migrated to jakarta.*. The folks at the Eclipse Foundation have taken great pains to make on-ramping to these new types as easy as possible, but it's still work that needs to be done. Work, I imagine, your IDE of choice will make it much easier.

InfoQ: For the first time since 2010, a Spring Framework update followed not one, but two years after the previous major release - version 5.3 in 2020. So it seems Spring Framework 6 had two years of development instead of one. What took so long? :-)  

Long: Hah. I hadn't even noticed that! If I'm honest, it feels like Spring Framework 6 has been in development for a lot longer than two years. This release has been one of incredible turmoil! Moving to Java 17 has been easy, but the migration to Jakarta EE has been challenging for us as framework developers. First, we had to sanitize all of our dependencies across all the supported Spring Boot libraries. Then we worked with, waited for, and integrated all the libraries across the ecosystem, one by one, until everything was green again. It was painstaking and slow work, and I'm glad it's behind us. But if we've done our jobs right, it should be trivial for you as a developer consuming Spring Boot.

The work for observability has also been widespread. The gist of it is that Micrometer now supports tracing, and there's a unified abstraction for both tracing and metrics, the Observation. Now for some backstory. In Spring Boot 2.x, we introduced Micrometer to capture and propagate metrics to various time-series databases like Netflix Atlas, Prometheus, and more. Spring Framework depends on Micrometer. Spring Boot depends on Spring Framework. Spring Cloud depends on Spring Boot. And Spring Cloud Sleuth, which supports distributed tracing, depends on Spring Cloud. So supported metrics at the very bottom of the abstraction stack and distributed tracing at the very top.

This arrangement worked, for the most part. But it meant that we had two different abstractions to think about metrics and tracing. It also meant that Spring Framework and Spring Boot couldn't support instrumentation for distributed tracing without introducing a circular dependency. All of that changes in Spring Boot 3: Spring Framework depends on Micrometer, and Micrometer supports both tracing and metrics through an easy, unified abstraction. 

And finally, the work for Ahead-of-Time (AOT) compilation with GraalVM Native Image landed officially in Spring Framework 6 (released on November 15, 2022). It has been in the works in some form or another since at least 2019. It first took the form of an experimental research project called Spring Native, where we proved the various pieces in terms of Spring Boot 2.x and Spring Framework 5.x. That work has been subsumed by Spring Framework 6 and Spring Boot 3. 

InfoQ:  As announced last year, the free support duration for Spring Framework 6.0 and 6.1 will be shorter. Both are down 20% to 21.5 months, compared to 27 months for Spring 5.2. In contrast, the free support duration for Spring Boot 3.0 remains one year. Why is that?

Long: We standardized the way support is calculated in late 2021. We have always supported open-source releases for 12 months for free. Each project can extend that support based on release cycles and their community needs, but 12 months of open-source support and 12 months of additional commercial support is what all projects have as the minimum. It’s normal for us to further extend support for the last minor release in a major generation (as we are doing with Spring Framework 5.3.x).

It’s important to note that the standardization of support timelines happened at the end of 2021. We had zero major or minor Spring Framework releases since that happened. Spring Framework 6 will be the first under the new guidelines.

Juergen Hoeller: It’s worth noting that the commercial support timeframe for Spring Framework 6.0 and 6.1 is shorter as well. We are not shortening the support of open-source releases in favor of commercial releases. Rather, it's all a bit tighter — the expectation is that people upgrade to the latest 6.x feature releases more quickly. Just like they also should be upgrading their JDK more quickly these days. In that sense, Spring Framework 5.x was still very much attached to the JDK 8 usage style of "you may stay on your JDK level and Java EE level." Spring Framework 6.x is meant to track JDK 17+ and Jakarta EE 9+ (both release more often than before) as closely as possible, adapting the release philosophy accordingly. 

InfoQ: Spring Boot 3 supports the GraalVM Native Image AOT compiler out of the box. This produces native Java applications that start faster, use less memory, have smaller container images, and are more secure. In which areas of cloud computing does this put Java on more equal footing against competitors such as Go?

Long: I don't know that I'd characterize Java as less or more on equal footing with Go. Regardless of Go, Java hasn't been the most memory-efficient language. This has foreclosed on some opportunities like IoT and serverless. AOT compilation with GraalVM Native Image puts it in the running while retaining Java's vaunted scalability and productivity.

InfoQ: In which areas of cloud computing will native Java not move the needle?

Long: I don't know. It feels like GraalVM Native Image will be a suitable replacement for all the places where the JRE might have otherwise been used. Indeed, GraalVM opens new doors, too. Developers can write custom Kubernetes controllers using Spring Boot now. You can write operating-system-specific client binaries like CLIs (hello, Spring Shell!).

InfoQ: Downsides of native Java are a slower, more complex build pipeline, less tool support, and reduced observability. The build pipeline disadvantages seem unavoidable — AOT compilation takes longer, and different operating systems need different executables. But how do you think tool support and observability in native Java will compare against dynamic Java in the medium term?

Long: IntelliJ already has fantastic support for debugging GraalVM native images. I don't think most people will mourn the loss of Java's vaunted portability. After all, most applications run in a Linux container running on a Linux operating system on a Linux host. That said, there is a fantastic GitHub Action that you can use to do cross-compilation, where the build runs on multiple operating systems and produces executables specific to those operating systems. You can use tools like Buildpacks (which Spring Boot integrates with out of the box, e.g.: mvn -Pnative spring-boot:build-image) to build and run container images on your macOS or Windows hosts. GraalVM's observability support has been hampered a bit because Java agents don't run well (yet) on in native executables. But, the aforementioned Micrometer support can sidestep a lot of those limitations and yield a more exhaustive result.

InfoQ: Talking about observability: That’s another headline feature of Spring 6. It encompasses logging, metrics, and traces and is based on Micrometer. Java has many observability options already. Why bake another one into Spring? And why now?

Long: Java doesn't really have a lot of things that do what Micrometer does. And we're not baking another one — we're enhancing an existing one that predates many distinct and singly focused alternatives. Micrometer has become a de-facto standard. Many other libraries already integrate it to surface metrics:

  • RabbitMQ Java client
  • Vert.x?
  • Hibernate
  • HikariCP
  • Apache Camel
  • Reactor
  • RSocket
  • R2DBC
  • DS-Proxy
  • OpenFeign
  • Dubbo
  • Skywalking
  • Resilience4J (in-progress)
  • Neo4J

InfoQ: How can I view and analyze the observability data from Spring 6 and Spring Boot 3 besides reading the data files directly?

Long: Micrometer provides a bevy of integrations with metrics tools like Graphite, Prometheus, Netflix Atlas, InfluxDB, Datadog, etc. It works with distributed tracing tools like OpenZipkin. It also integrates with OpenTelemetry ("OTel"), so you can speak to any OTel service.

InfoQ: Spring Boot 3 won’t fully support Native Java and observability in all its projects and libraries at launch. How will I know if my Spring Boot 3 application will work in native Java and provide complete observability data?

Long: This is only the beginning of a longer, larger journey. The surface area of the things that work well out-of-the-box with GraalVM Native Image grows almost daily. There's no definitive list, but you should know that all the major Spring projects have been working on support. It's our priority. Check out our Spring AOT Smoke Tests to see which core projects have been validated.

InfoQ: Which upcoming feature of Java excites you the most?

Long: I am super excited about three upcoming bodies of work: Project Loom, Project Leyden, and Project Panama. Project Loom brings lightweight green threads to the JVM and promises to be a boon to scalability. Project Leyden seems like it'll give the application developer more knobs and levers to constrain and thus optimize their JVM applications. One of the more dramatic constraints looks to be GraalVM Native Images. And Project Panama looks to finally make Foreign-Function access as pain-free as it is in languages like Python, Ruby, PHP, .NET, etc. These three efforts will bring Java to new frontiers.

InfoQ: If you could make one change to Java, what would that be?

Long: Structural lambdas! I want real lambdas in Java. Right now, lambdas are a bit more than syntax sugar around single-abstract method interfaces. All lambdas must conform to a well-known single abstract method (SAM) interface, like java.util.function.Function<I,O>. This was fine before Java added the var keyword, which I love. But it's aesthetically displeasing now because of the need to tell the compiler to which interface a given lambda literal conforms. 

Here's some code in Kotlin:

val name = "Karen" // a regular variable of type String
val myLambda: (String) -> Int = { name -> name.length } // a lambda taking a string and returning an int

Here's the equivalent code in Java:

var name = "Karen";
var myLambda = new Function<String, Integer>() {
  @Override
  public Integer apply(String s) {
    return s.length();
  }
};

There are ways around this: 

var name = "Karen";
Function<String, Integer> myLambda = s -> s.length(); 

This is what I mean by it being aesthetically displeasing: either I abandon the consistency of having both lines start with var, or I abandon the conciseness of the lambda notation. 

Is this likely to ever get fixed? Probably not. Is it a severe issue? Of course not. On the whole, Java's a fantastice language. And most languages should be lucky to have gotten to Java's ripe old age with as few idiosyncratic syntax oddities as it has!

InfoQ: And what would your one change to Spring or Spring Boot be?

Long: This is a tough one! I wish we could bring back and renew Spring Rich, a now long-since defunct framework for building desktop Swing-powered client applications. Griffon is the only thing that addresses this space. It's a shame, because Spring could be great here, especially now that it has deeply integrated GraalVM Native Image support. Admittedly, this is probably a niche use case, too :) 

InfoQ: Josh, thank you for this interview.

 

About the Authors

Rate this Article

Adoption
Style

BT