Getting started with Spring and Coroutines - Part 1

Getting started with Spring and Coroutines - Part 1

Fully reactive

Ronny Bräunlich's photo
Ronny Bräunlich
·Jul 8, 2022·

3 min read

What I have seen several times among my colleagues and myself is that Coroutines are often regarded as an interesting topic, but developers are quite reluctant to use them. I suppose it is a mixture of the learning curve and bad experiences with Java threads, since most of us were Java developers. Or as Matt Wynne once wrote on Twitter:

I had a problem, so I decided to use threads. tNwoowp rIo bhlaevmes.

Still, it is surprisingly easy to get started with Coroutines in Spring. When using Webflux, we get Coroutine support. One disclaimer about Coroutines has to be mentioned here: Coroutines won't make our code automagically thread safe. We still have to consider possible concurrency issues. Anyways, working with Coroutines, the code looks more familiar than when working e.g., with Webflux/Reactor because the code looks like sequential code and is not cluttered with all the map(), flatMap(), switchIfEmpty().... calls.

To encourage the usage of Coroutines I decided to write some small blog posts, highlighting my experiences. Additionally, in my projects, I could see a substantial performance boost after switching to Coroutines. In this part we will cover the easiest case, staying reactive from the controller to the repository.

Reactive from the controller to the repository

The easiest way to get started with Coroutines in Spring is when you have spring-boot-starter-webflux in your classpath and your database driver is also reactive. In that case most of the work is just adding the suspend keyword. But let's take a look at an example.

The RestController

The controller is nothing special, it just needs the suspend keyword:

@RestController
class TestController(private val repository: EntityRepository) {

    @GetMapping(path = ["/entity/{id}"])
    suspend fun getEntity(@PathVariable id: String) = repository.findById(ObjectId(id))

}

When you set a breakpoint in the method you can see that Spring, using Reactor, started a Coroutine for us. We do not have to handle any contexts.

To keep the example short, I did not create a Service class. So next, let's take a look at the repository.

The repository

The repository looks slightly different than usual:

interface EntityRepository: CoroutineCrudRepository<TestEntity, ObjectId>

Spring introduced a CoroutineCrudRepository some time ago, in which all methods are suspend functions. In my example I use the reactive MongoDB driver. Therefore, everything is reactive by default and I do not have to add any additional configuration. Furthermore, my code looks like the usual sequential code one is used to read.

Conclusion

As you can see from the code, we hardly recognize that we are using Coroutines (still, keep in mind that you code must be thread-safe!). Of course, the example is very simple and nowhere close to the complexity of a real-world project. Still, it is a starting point. In the following article we will see how we can bridge the gap to a non-reactive database driver.

You can find the complete example on GitHub.

Did you find this article valuable?

Support Ronny Bräunlich by becoming a sponsor. Any amount is appreciated!

Learn more about Hashnode Sponsors
 
Share this