Micronaut: Introduction

Prologue Link to heading

As I am approaching my 40s its becoming harder and harder to get really excited with a new framework. There are of course some exception to this rule and micronaut is such an exception. I won’t get into details here, but in many ways I feel that micronaut is a framework I would like to have written myself…

So, this post is going to be a first look at micronaut. It will include:

  • an introduction
  • my first application
  • packaging the application as a docker image
  • packaging and running inside openshift.

What is micronaut? Link to heading

According to the official documentation micronaut is a micro services framework, for building modular and testable microservice applications. Some highlights:

  • Own DI
  • Autoconfiguration
  • Service Discovery
  • Http Routing

and more…

The framework has been created from the same team that brought us grails and it does look like it in many ways. When it comes to features however, it feels like a combination of spring boot and spring cloud that promises to be more lightweight.

More lightweight? Link to heading

Traditional DI approaches in Java be it spring, CDI etc, is built around reflection, proxies etc. Not so long ago there was an effort aiming mostly mobile devices that was built around the idea of handling most of the problem at compile time instead of runtime. The project was called dagger. I am not sure how it went in terms of adoption, but I didn’t feel it ever had a strong presence in the enterprise world.

What does these have to do with micronaut?

micronaut is using a similar approach with dagger, relying more on annotation processors instead of using reflection, proxies etc.

Getting started Link to heading

The first thing one needs to get started with micronaut is the `mn` binary, which gives you access to a grails-like cli:

Installation Link to heading

To install the `mn` the documentation suggests the use of sdkman (I’ve also blogged on sdkman here).

1
sdk install micronaut

Creating a hello world example Link to heading

Once the installation is complete you can create a new micronaut application using the cli:

1
mn create-app helloworld

The generated project is a docker-ready gradle project that contains just a single class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package helloworld;

import io.micronaut.runtime.Micronaut;

public class Application {

    public static void main(String[] args) {
        Micronaut.run(Application.class);
    }
}

Note, that options are provided to select language, build tool and testing framework.

This will be very familiar to spring boot users.

Now, let’s see how we can create a rest controller. From within the helloworld directory:

1
mn create-controller HelloController

The command will generate the controller class and also a test for the controller.

The controller out of the box will just provide a single method that returns http status `OK`. That can be easily modified, to:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package helloworld;

import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;

@Controller("/hello")
public class HelloController {

    @Get("/")
    public String index() {
        return "Hello World!";
    }
}

To run the application you can just use:

1
./gradlew run

Noteworthy Link to heading

It seems that its possible to specify things like language and testing framework not only on application level but also on controller level too. So for instance we can add a second controller in kotlin:

1
mn create-controller KotlinController --lang kotlin

The code generation part worked a treat, however I wasn’t able to get the kotlin controller (inside a java project) running even when I manually added the kotlin plugin inside the `build.gradle` file.

Packaging the application Link to heading

As mentioned above the generated app is docker-ready. Meaning that it comes with a docker file.

1
docker build -t iocanel/mn-helloworld:latest .

The first time I tried to build the image, it failed and that was due to the fact that the docker build relies on copying the jar that’s expected to be build locally. While, I am not against this approach, when its not coordinated by an external tool (e.g. fabric8 maven plugin) it does feel a bit weird.

Second attempt:

1
2
./gradlew build
docker build -t iocanel/mn-helloworld:latest .

This time everything worked smoothly! Let’s see what we got in terms of size and startup times compared to spring boot.

jaruberjardockerstartup time
micronaut1.4K12M114M0.892 sec
spring boot3.416M119M2.232 sec

Please note that these measurements are simplistic, they are not meant to prove anything and are there just give a very rough idea of the overall behavior of micronaut.

Packaging and running inside Openshift Link to heading

For vanilla kubernetes the packaging process doesn’t differ much. In this section I’ll describe how you can package and run the application in openshift.

The first step is to define a binary build. The binary build will use the `source to image` for java. Once the build is defined, we can start it and pass the folder that contains the micronaut uberjar as a parameter.

1
2
  oc new-build --binary --strategy=source --name=helloworld fabric8/s2i-java:2.3
  oc start-build helloworld --from-dir=./build/libs --follow

The resulting image will include the uberjar under /deployments (this is how the fabric8 s2i image works). So all we need, is to start a new app and just tell the container which jar to use.

1
  oc new-app helloworld:latest -e JAVA_APP_JAR=/deployments/helloworld-0.1-all.jar

This will create a new DeploymentConfig and a service for our application. In a few seconds the application will be up and running. Let’s try it out.

Exposing our application Link to heading

The service that was created by the `oc new-app` command will NOT expose port 8080 which is what we need. That’s because the `fabric8/s2i-java` image doesn’t expose it (feel free to correct me here if I missed something). So, we will delete the generated service and create and expose one that matches our needs.

1
2
3
  oc delete svc helloworld
  oc expose dc helloworld --port 8080,8787,9779
  oc expose svc helloworld

This will create the service exposing port 8080 and also expose the service to `http://helloworld-micronaut.127.0.0.1.nip.io`.

Now, its just a matter of using curl:

1
curl helloworld-micronaut.127.0.0.1.nip.io/hello

Epilogue Link to heading

I think that this is enough for a first look.

I intend to write additional posts in order to try out things like:

  • hooking a database
  • using circuit breakers
  • tracing
  • more …