1. What is Micronaut
Micronaut is a JVM framework for building lightweight modular applications. It was developed by OCI, the same company that gave us Grails. Micronaut is a modern framework designed to make the creation of microservice applications quick and easy.
Micronaut contains features similar to existing frameworks, such as Spring, but at the same time it implements some new ideas that are its distinctive features. Along with support for Java, Groovy and Kotlin, it offers many ways to create applications.
2. Main features
One of the most exciting features of Micronaut is dependency injection (DI) at compile time. Most frameworks use reflection and proxy objects to inject dependencies during execution. Micronaut also collects data for dependency injection at compile time. The result of this is a quick start time for applications and less memory consumption.
')
His next opportunity is first-class support for reactive programming for both clients and servers. The choice of a specific implementation of the reactive approach is left to the developers of the solutions, and RxJava and Project Reactor are supported out of the box.
Plus, Micronaut has several features that make it an excellent framework for developing cloud applications (cloud-native). It supports many service discovery mechanisms, such as Eureka and Consul, and also works with various distributed tracing systems, such as Zipkin and Jaeger.
Additionally, it provides support for creating AWS lambda functions, making it easy to create serverless applications (serverless).
3. Getting started
The easiest way to get started is to use SDKMAN:
> sdk install micronaut 1.0.0.M2
SDKMAN installs all the binary files you need to build, test and deploy Micronaut applications. In addition, you will receive the console application Micronaut CLI, which allows you to easily start a new project.
Binary artifacts are also available in Sonatype and on Github.
In the following sections, we look at some of the features of Micronaut.
4. Dependency Injection (DI)
As mentioned earlier, Micronaut handles dependency injection at compile time, which distinguishes it from most IoC containers.
However, it fully supports JSR-330 annotations, so working with bins is similar to other IoC frameworks.
To inject a bin in our code, we use
@Inject
:
@Inject private EmployeeService service;
The
@Inject
annotation
@Inject
works like
@Autowired
and can be used with fields, methods, constructors, and parameters.
By default, all beans have a scope - prototype. We can quickly create singletones using the
@Singleton
annotation. If multiple bins implement the same interface, we can use the
@Primary
annotation to resolve the conflict:
@Primary @Singleton public class BlueCar implements Car {}
The
@Requires
can be used when the bins are optional, or to perform an injection when certain conditions are met.
In this regard, it behaves in the same way as the Spring Boot annotation is
@Conditional
.
@Singleton @Requires(beans = DataSource.class) @Requires(property = "enabled") @Requires(missingBeans = EmployeeService) @Requires(sdk = Sdk.JAVA, value = "1.8") public class JdbcEmployeeService implements EmployeeService {}
5. Create HTTP server
Now, let's try creating a simple HTTP server application. To get started, we will use SDKMAN:
> mn create-app hello-world-server -build maven
So we will create a new Java project with Maven in a directory called hello-world-server. Inside this directory we will find the main application code, Maven POM file and other project files.
The simplest application looks like this:
public class ServerApplication { public static void main(String[] args) { Micronaut.run(ServerApplication.class); } }
5.1 Blocking HttpRequest
In itself, the application does almost nothing. Let's add a controller with two handlers. Both will return a greeting, but one will respond to GET requests, and the other to POST.
@Controller("/greet") public class GreetController { @Inject private GreetingService greetingService; @Get("/{name}") public String greet(String name) { return greetingService.getGreeting() + name; } @Post(value = "/{name}", consumes = MediaType.TEXT_PLAIN) public String setGreeting(@Body String name) { return greetingService.getGreeting() + name; } }
From the translator: your humble servant went and did everything that is described in this article. If at this stage you are going to start the application and see if it works, then do not forget to enable Annotation Processing in Eclipse / IntelliJ IDEA.5.2 Reactive IO
By default, Micronaut implements these handlers as traditional blocking I / O. However, we can quickly implement non-blocking handlers, all by changing the return type to any of the reactive non-blocking types.
For example, with RxJava we can use
Observable
. Similarly, with Reactor, we can return
Mono
or
Flux
types:
@Get("/{name}") public Mono<String> greet(String name) { return Mono.just(greetingService.getGreeting() + name); }
From the translator: for this example you will need a Project Reactor in the Maven dependencies: <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-core</artifactId> <version>3.1.8.RELEASE</version> </dependency>
Both blocking and non-blocking handlers use the HTTP server Netty.
Usually, requests are processed in the main I / O thread pool, which is created at startup, which makes them blocked.
However, if the handler returns non-blocking data types, Micronaut uses the Netty event-handling cycle, making the entire request non-blocking.
6. Create HTTP client
Now, let's create a client application for the handlers that we just created. Micronaut provides two ways to create HTTP clients:
- declarative
- software
6.1 Declarative HTTP client creation
The first and easiest way to create uses a declarative approach:
@Client("/greet") public interface GreetingClient { @Get("/{name}") String greet(String name); }
Notice, we have not implemented a single line of code to call the service. Instead, Micronaut understands how to call the service from the method signature and annotations.
To test this client, we can create a JUnit test that uses the server API to run the embedded server:
public class GreetingClientTest { private EmbeddedServer server; private GreetingClient client; @Before public void setup() { server = ApplicationContext.run(EmbeddedServer.class); client = server.getApplicationContext().getBean(GreetingClient.class); } @After public void cleanup() { server.stop(); } @Test public void testGreeting() { assertEquals(client.greet("Mike"), "Hello Mike"); } }
From the translator: for lazy inquisitive readers there is a ready project on Github: github.com/jreznot/micronaut-introduction6.2 Software creation of HTTP client
There is an option to create a traditional HTTP client if you need more control over its behavior and implementation:
@Singleton public class ConcreteGreetingClient { private RxHttpClient httpClient; public ConcreteGreetingClient(@Client("/") RxHttpClient httpClient) { this.httpClient = httpClient; } public String greet(String name) { HttpRequest<String> req = HttpRequest.GET("/greet/" + name); return httpClient.retrieve(req).blockingFirst(); } public Single<String> greetAsync(String name) { HttpRequest<String> req = HttpRequest.GET("/async/greet/" + name); return httpClient.retrieve(req).first("An error as occurred"); } }
The client uses RxJava by default, so you can easily use blocking and non-blocking calls.
7. Micronaut CLI
We have already seen how the Micronaut CLI utility works when creating the application.
In our case, it was a separate application, but this utility supports several other features.
7.1 Projects from a variety of applications (Federation)
In Micronaut, conversion is simply a group of separate applications that are developed in one project. Using federation we can easily manage all of them together and make sure that they use the same settings.
When we use the CLI to generate a federation, the utility takes the same arguments as the create-app command. It will create the main project directory and put each application in a subdirectory.
7.2 Features
When creating an application or a federation, we can choose which features our application needs. This allows the use of a minimal set of dependencies in a project.
We specify the possibilities in the seen
-features
argument, separated by commas.
You can display a list of available options using the following command:
> mn profile-info service Provided Features: -------------------- * annotation-api - Adds Java annotation API * config-consul - Adds support for Distributed Configuration with Consul * discovery-consul - Adds support for Service Discovery with Consul * discovery-eureka - Adds support for Service Discovery with Eureka * groovy - Creates a Groovy application [...] More features available
From the translator: well, don't be surprised here, the command should be run outside the project directory. The project directory does not work, it can be repaired in the .M3 version. She has already left.7.3 Existing Projects
We can use CLI to modify existing projects. This allows us to create bins, clients, controllers, etc. When we run the “mn” command in the project directory, we will have the following commands available:
> mn help | Command Name Command Description
8. Conclusion
In this brief introduction to Micronaut, we looked at how easy it is to create blocking and non-blocking HTTP servers and clients. We also looked at a couple of CLI features.
This is just a small piece of cake, which offers Micronaut. Under the hood, it has support for serverless functions, service discovery, distributed tracing, monitoring and metrics, distributed configurations, and much more.
However, the fact that many features of Micronaut were borrowed from existing frameworks such as Grails and Spring, it offers unique features that distinguish it from others.