This Month in Spring - December 2021

December 21, 2021 Josh Long

Hi, Spring fans! Welcome to another installment of This Month in Spring! Can you believe we're staring down 2022? It's already almost the end of the year! I can't believe we quickly got this far, but we did.

There have been several things I want to draw your attention to since last month, not least of which is the information about Log4j2 and the new Spring Native release.

Log4j2 is the gift that keeps on giving

Log4j2 isn't a problem. I am so grateful to all the developers who work on Log4j2 so that we can use it. Vulnerabilities happen, and they happen to everybody. So, I wish people would try to remember that Log4j2 has served countless people just fine for a very, very long time. While there is a vulnerability, the vulnerability is easy to fix. If you're a Spring Boot developer using the default, out-of-the-box settings in a Spring Boot application, then you've got nothing to fear. I'll repeat it: unless you've explicitly opted into Log4j2, you should be fine. However, a new Logback issue could, in theory, affect Spring Boot developers. It's a much more complex vulnerability to exploit, however. That doesn't mean it's not worth your attention. Be careful out there, friends: wear a mask and patch your software!

Spring Native 0.11

Moving on to things more tantalizing: we released Spring Native 0.11, which is fantastic because it features a brand new AOT (ahead-of-time) engine that completely reworks how we transpile Spring Boot applications into GraalVM native images. I've been working with GraalVM a lot over the last two years, and this new release is a vast, revolutionary step in the story of Spring Native and a giant leap forward on the journey to Spring Framework 6 and Spring Boot 3, both of which will land next year.

I've been tinkering with the new release a lot over the last month, too. Spring Native works well for a ton of use cases supported by Spring itself, and so, for most applications, I've found things work just fine with no changes. That said, some things will not work in a Spring Native context or any GraalVM context without some help. For example, it would help if you told GraalVM what you're doing that might confound it - proxies, serialization, resource-loading, etc. Spring Native provides a mechanism - hints - by which you can do this. It's easy. But it still has to be done. So, I've been going around to some projects that I think would probably need some help and trying to make them work.

MyBatis and Spring Native

I got Spring and MyBatis to work well and put that in a sample branch. See this blog for more on that. It was challenging to get Spring and the MyBatis Spring Boot autoconfiguration to work. I started rebuilding the autoconfiguration, bit by bit, and managed to build an inarguably less helpful, less robust Spring Boot autoconfiguration for MyBatis that works well with Spring Native, too. I'm already talking to some folks on the MyBatis team about possibly including some of this work. (Fingers crossed!). With this proof-of-concept Spring Boot autoconfiguration and Spring Native configuration, you can create a MyBatis SQL Mapper like this:

@Mapper
public interface CityMapper {

   @Insert("INSERT INTO city (name, state, country) VALUES(#{name}, #{state}, #{country})")
   @Options(useGeneratedKeys = true, keyProperty = "id")
   void insert(City city);

   @Select("SELECT id, name, state, country FROM city ")
   Collection findAll();
}  

Spring Retrosocket and Spring Native

I also updated the Spring Retrosocket project to work with Spring Native. Spring Retrosocket is a declarative Feign- or Retrofit-like client for RSocket-based services.

@RSocketClient
interface GreetingsClient {

   @MessageMapping("hello")
   Mono hello(Mono name);
} 

The Kubernetes Java Client and Spring Native

Then, I turned my attention to making the Kubernetes Java client work well in a Spring Native and GraalVM context. The Kubernetes Java client is essential if you want to build memory-efficient controllers and operators for Kubernetes. Did I mention that GraalVM native images are very memory efficient? It depends on what you're doing in your application, of course, but my typical applications end up taking anywhere from 40 to 55 megabytes of RAM (well, RSS, specifically). And that's in addition to startup in only tens of milliseconds. The official Kubernetes-for-Java client has a Spring Boot autoconfiguration. So all I had to do was write the trivial Spring Native configuration required to make such applications work well in a Spring Native and GraalVM context. I explain it here in detail. Suffice it to say it's now possible to use your favorite development framework not just to build excellent Kubernetes resources and controllers but deploy them in a low-footprint fashion to your organization's clusters.

Spring GraphQL and Spring Native

Then, I turned my attention to Spring GraphQl and Spring Native. Spring GraphQL works pretty well as long as you override how the GraphQlSourceBuilder derives the Spring Framework Resource instances used to feed the engine the schema for your GraphQL endpoints. It's not as easy as it could be, but it's still only an extra @Bean or two or so lines of code to make it work. Fine. The trouble starts when you're using Spring GraphQL and want to query the metamodel for Spring GraphQL's schema itself. Having the GraphQL metamodel is convenient when, for example, you're using the /graphiql/ interactive console to query the data. That took some doing, but I did it. I explain that further in this post.

With that, I can deploy a GraphQL controller like this:

@Controller
class CustomerGraphQlController {

   private final CustomerRepository repository; 
   CustomerGraphQlController(CustomerRepository repository) {
      this.repository = repository ;
   } 
   @QueryMapping
   Flux customers() {
    return this.repository.findAll();  
   }
}

record Customer(@Id Integer id, String name) { } 

...that uses the following schema:

type Query { customers : [Customer] } type Customer { id: ID name :String } 

Then open the example up at http://localhost:8080/graphiql/ and issue the following query:

query { customers { id, name } } 

And get the results I was expecting!

Miscellaneous

I've also been dealing with many other things I wanted to get working with Spring Native. So here's the Spring Native configuration for CommonMark, a Markdown parser in Java.

Here are the various classes I had to add to make Apache Lucene work in a Spring Native project. Of course, this example is more involved and uses GraalVM substitutions and a typical Spring Native configuration. But it works, and well, too!

Oh, and did I mention I worked with Ronald Dehuysser to get Jobrunr, a distributed job scheduling engine, working in a GraalVM context with Spring Native? Because I did, and the result is awesome!

I've done all this in just the last few weeks: the possibilities are endless, and I can't wait to see more and more of the wide and world of Springdom sprout GraalVM integrations.

Anyway, enough of this ever-so-indulgent discussion of building GraalVM and native applications; we've got a ton of good stuff to review this month, so let's dive into it!

About the Author

Josh Long (@starbuxman) is a Spring Developer Advocate at VMware. Josh is a Java Champion, a Google Developer Expert for Kotlin, author of six books (including O'Reilly's "Cloud Native Java: Designing Resilient Systems with Spring Boot, Spring Cloud, and Cloud Foundry") and the just released "Reactive Spring" (ReactiveSpring.io), six best-selling Livelessons video trainings (including "Building Microservices with Spring Boot Livelessons" with Phil Webb and "Spring Security Livelessons" with Rob Winch, and "Cloud Foundry Livelessons" with Josh McKenty), and an open-source contributor (Spring Boot, Spring Integration, Spring Cloud, Activiti and Vaadin). Josh also has a podcast, "A Bootiful Podcast," and does a series of screencasts, "Spring Tips", on YouTube (bit.ly/spring-tips-playlist). Josh routinely blogs on the Spring blog (spring.io/blog)

Follow on Twitter Visit Website More Content by Josh Long
Previous
CNCF-Certified Solutions Now Qualify for VMware’s Partner-Ready Badge
CNCF-Certified Solutions Now Qualify for VMware’s Partner-Ready Badge

Certified Kubernetes solutions will automatically qualify for VMware’s Partner Ready for Tanzu badge.

Next
Automatically Manage DNS for Kubernetes with ExternalDNS and Tanzu Mission Control Catalog
Automatically Manage DNS for Kubernetes with ExternalDNS and Tanzu Mission Control Catalog

This guide shows how to deploy the ExternalDNS plug-in via Tanzu Mission Control Catalog for use with AWS R...