The evolution of Spring Fu

Engineering | Sébastien Deleuze | October 02, 2018 | ...

I take the opportunity of a short stop between SpringOne platform where I gave the first talk about Spring Fu and Kotlinconf to give an overview of the evolution of this project, summarize the current status and share what could be the next steps.

Early June, I announced a new experimental project named Spring Fu, with the goal to experiment on a new kind of API to configure Spring applications using Kotlin DSL and functional configuration.

I must admit I was not expecting the huge wave of feedback that followed, and I would like to thank the Spring community for such warm welcome. I have continued since to work on the project in order to turn this first POC based on raw Spring Framework API into an incubator for new Spring functional features.

Kofu configuration

The Kotlin DSL is now based on Spring Boot infrastructure and is called Kofu (for Kotlin and functional). It allows to configure Spring Boot applications with a Kotlin DSL and lambdas instead of annotations and have following characteristics:

  • Explicit configuration via a Kotlin DSL
  • Based on Spring Boot infrastructure used in a functional way
  • No feature enabled based on classpath detection
  • Both declarative and programmatic
  • Faster startup and lower memory consumption
  • Minimal reflection & annotations usage
  • Pure lambdas, no CGLIB proxy

A typical Spring Boot application configured with Kofu configuration looks like that:

val app = application {
  import(beans)
  listener<ApplicationReadyEvent> {
    ref<UserRepository>().init()
  }
  properties<SampleProperties>("sample")
  server {
    port = if (profiles.contains("test")) 8181 else 8080
    mustache()
    codecs {
      string()
      jackson {
        indentOutput = true
      }
    }
    import(::routes)
  }
  mongodb {
    embedded()
  }
}

val beans = beans {
  bean<UserRepository>()
  bean<UserHandler>()
}

fun routes(userHandler: UserHandler) = router {
  GET("/", userHandler::listView)
  GET("/api/user", userHandler::listApi)
  GET("/conf", userHandler::conf)
}

fun main() = app.run()

In order to use it, you "just" have to add a org.springframework.fu:spring-boot-kofu dependency to a Spring Boot 2.1 application. As the current version number 0.0.2 suggests it, be aware that for now the API is not stable yet, not suitable for production and that the scope is limited to a subset of what Spring Boot supports.

But feel free to play with it, send feedback and try this new way of configuring Spring Boot applications which is functional, discoverable via your IDE auto-complete and documented.

Kofu is not better or worse than auto-config, it is just different. I believe it could be a way for Spring Boot to reach developers who prefer a more explicit configuration model and those who are coming from other backgrounds like Kotlin, Go, Node or Ruby.

Jafu configuration

Initially limited to Kotlin, one of the main feedback I received was from Java developers interested in this explicit DSL approach as well, so I worked on a Java equivalent and ended up with this Jafu (for Java and functional) DSL.

public class JafuApplication {

  public static SpringApplication app = application(app -> {
    app.beans(beans -> {
      beans.bean(SampleService.class);
      beans.bean(SampleHandler.class);
    });
    app.server(server -> server.router(router -> {
      SampleHandler sampleHandler = app.ref(SampleHandler.class);
      router.GET("/", sampleHandler::hello);
      router.resources("/**", new ClassPathResource("static/"));
    }));
  });

  public static void main (String[] args) {
    app.run(args);
  }
}

This is currently just a POC but I plan to reach feature parity shortly with Kofu and develop the 2 DSLs in parallel. The lack of type-safe builders, reified type parameters or extension mechanism will make Jafu more verbose and less extensible than Kofu, but despite these limitations, I find Jafu pretty nice and usable.

For users only interested by the performance increase linked to the usage of a functional bean registration infrastructure, it is worth to notice than Dave Syer is currently experimenting on solutions that would make it possible to leverage functional bean registration efficiency with regular Spring Boot applications based on annotations.

Running Spring applications as native executable

GraalVM is a new virtual machine developed by Oracle, which allows among other features, to compile JVM bytecode to native executable via Substratevm.

Spring Framework 5.1 provides some initial support for GraalVM native images, but we are really at the beginning of the story. GraalVM team need to fix various issues raised by Dave in order to get everything working as expected, and the ecosystem needs to adap to this new platform which has different constraints and characteristics.

But GraalVM team is listening our feedback, and Spring application support has progressed significantly these last months. It is already possible to compile a basic Spring Boot reactive application with Kofu configuration as a native executable that runs almost instantly!

Coroutines support

Like said before, the main goal of Spring Fu is to incubate features that will be integrated in current top level projects like Spring Framework, Spring Data and Spring Boot.

Spring Fu is currently incubating coroutines support for Spring WebFlux and Spring Data in order to be able to leverage Spring Reactive stack in a more imperative style fashion. This mainly targets developers who want to leverage the scalability of such stack without requiring all the power of reactive API.

class UserRepository(private val mongo: CoroutinesMongoTemplate) {
	suspend fun count(): Long = mongo.count<User>()
	suspend fun findAll(): List<User> = mongo.findAll<User>()
	suspend fun findOne(id: String): User? = mongo.findById<User>(id)
	suspend fun deleteAll() = mongo.remove<User>()
	suspend fun save(user: User): User? = mongo.save(user)
}

Be aware that while coroutines are considered final as of Kotlin 1.3, there is still a major missing piece in kotlinx-coroutines since it does not provide any type to deal with cold streams. We will need this missing abstraction in order to be able to expose our reactive foundations with a coroutines API, see kotlinx.coroutines#254 for more details.

Notice that we should be able to pass context between coroutines and reactor types in order to allow pretty powerful use cases like reactive security and transactions.

Konrad Kaminski who contributed the original Spring coroutines support via his great spring-kotlin-coroutine project will shortly join Spring Fu to work on this feature with me.

Conclusion

I have just released Spring Fu 0.0.2 which provides an improved Kofu DSL and introduces autowiring of function parameters. Feel free to try it and to provide feedback.

Upcoming Spring Fu 0.0.3 will provide feature parity between Kofu and Jafu configurations.

We already have 10+ community contributors who submitted pull requests to Spring Fu, so if you have some ideas you could maybe be the next ;-)

Looking forward meeting you in my upcoming Spring Fu talks at JFuture (Minsk), Spring Fest (Tokyo) and Devoxx (Antwerpen).

Get the Spring newsletter

Stay connected with the Spring newsletter

Subscribe

Get ahead

VMware offers training and certification to turbo-charge your progress.

Learn more

Get support

Tanzu Spring offers support and binaries for OpenJDK™, Spring, and Apache Tomcat® in one simple subscription.

Learn more

Upcoming events

Check out all the upcoming events in the Spring community.

View all