1. Overview
In this tutorial, we’re going to compare Micronaut and Spring Boot. Spring Boot is a part of the popular Spring framework used for getting Spring applications up and running quickly. Micronaut is a JVM-based framework created to address some of the weaknesses of Spring/Spring Boot.
We’ll compare the two frameworks in several areas. First, we’ll compare the ease of creating a new application, language support, and other configuration options. Then we’ll look at two simple REST applications. Finally, we’ll compare the code and measure performance differences.
2. Features
In the following sections, we’ll break down several features in the two frameworks.
2.1. Setup
First, we’ll compare the ease of getting a new application up and running in the two frameworks.
Both Micronaut and Spring Boot offer multiple convenient methods for creating new applications. For example, we can create a new application using either framework with a command-line interface. Alternatively, we could use the Spring Initializr for Spring Boot or a similar tool for Micronaut called Launch.
In terms of IDE support, we can use Spring Boot plugins for most popular IDEs, including its flavor of Eclipse, the Eclipse Spring Tools Suite. We have a Micronaut plugin available to us if we’re using IntelliJ.
2.2. Language Support
As we turn to language support, we’ll find that it’s nearly identical for Spring Boot and Micronaut. For both frameworks, we can choose between Java, Groovy, or Kotlin. If we choose Java, both frameworks support Java 8, 11, and 17. Additionally, we can use either Gradle or Maven with both frameworks.
2.3. Servlet Container
Using Spring Boot, our application will use Tomcat by default. However, we can configure Spring Boot to use either Jetty or Undertow as well.
Our Micronaut applications will, by default, run on a Netty-based HTTP Server. However, we can choose to switch our application to run on Tomcat, Jetty, or Undertow.
2.4. Properties Configuration
For Spring Boot, we can define our properties in application.properties or application.yml. We can use the application-{env}.properties convention to provide different properties for different environments. Additionally, we can override these applications file provided properties using system properties, environment variables, or JNDI attributes.
We can use application.properties, application.yml, and application.json for our properties files in Micronaut. We can also use the same convention for supplying environment-specific properties files. If we need to override any properties, we can use system properties or environment variables.
2.5. Messaging Support
If we’re using messaging with Spring Boot, we have Active MQ, Artemis, Rabbit MQ, and Apache Kafka available to us.
On the Micronaut side, we have Apache Kafka, Rabbit MQ, and Nats.io as options.
2.6. Security
Spring Boot offers five authorization strategies: basic, form login, JWT, SAML, and LDAP. If we’re using Micronaut, we have the same options minus the SAML.
Both frameworks provide us with OAuth2 support.
In terms of actually applying the security, both frameworks allow us to use annotations to secure methods.
2.7. Management and Monitoring
Both frameworks provide us with the ability to monitor various metrics and statistics in our applications. We can define custom endpoints in both frameworks. We also can configure endpoint security in both frameworks.
However, the Spring Boot actuator provides several more built-in endpoints than Micronaut.
2.8. Template Languages
We can create complete full-stack applications with both frameworks, using provided template languages to render the front-end.
For Spring Boot, our choices are Thymeleaf, Apache Freemarker, Mustache, and Groovy. We can also use JSP, although the practice is discouraged.
We have a few more options available in Micronaut: Thymeleaf, Handlebars, Apache Velocity, Apache Freemarker, Rocker, Soy/Closure, and Pebbles.
2.9. Cloud Support
Spring Boot applications rely on third-party libraries for many cloud-specific features.
Micronaut is natively designed for cloud microservices. Cloud concepts that Micronaut will natively handle for us include distributed configuration, service discovery, client-side load balancing, distributed tracing, and serverless functions.
3. The Code
Now that we’ve compared some basic features in the two frameworks, let’s create and compare two applications. To keep things simple, we’ll create a simple REST API that solves basic arithmetic problems. Our service layer will consist of a class that actually does the math for us. Our controller class will contain an endpoint for addition, subtraction, multiplication, and division.
Before we dig into the code, let’s consider a significant difference between Spring Boot and Micronaut. Although the two frameworks provide dependency injection, they go about it differently. Our Spring Boot application handles dependency injection at runtime using reflection and proxies. In contrast, our Micronaut application builds dependency injection data when it’s compiled.
3.1. The Spring Boot Application
First, let’s define a class in our Spring Boot application called ArithmeticService:
@Service
public class ArithmeticService {
public float add(float number1, float number2) {
return number1 + number2;
}
public float subtract(float number1, float number2) {
return number1 - number2;
}
public float multiply(float number1, float number2) {
return number1 * number2;
}
public float divide(float number1, float number2) {
if (number2 == 0) {
throw new IllegalArgumentException("'number2' cannot be zero");
}
return number1 / number2;
}
}
Next, let’s create our REST controller:
@RestController
@RequestMapping("/math")
public class ArithmeticController {
@Autowired
private ArithmeticService arithmeticService;
@GetMapping("/sum/{number1}/{number2}")
public float getSum(@PathVariable("number1") float number1, @PathVariable("number2") float number2) {
return arithmeticService.add(number1, number2);
}
@GetMapping("/subtract/{number1}/{number2}")
public float getDifference(@PathVariable("number1") float number1, @PathVariable("number2") float number2) {
return arithmeticService.subtract(number1, number2);
}
@GetMapping("/multiply/{number1}/{number2}")
public float getMultiplication(@PathVariable("number1") float number1, @PathVariable("number2") float number2) {
return arithmeticService.multiply(number1, number2);
}
@GetMapping("/divide/{number1}/{number2}")
public float getDivision(@PathVariable("number1") float number1, @PathVariable("number2") float number2) {
return arithmeticService.divide(number1, number2);
}
}
Our controller has an endpoint for each of the four arithmetic functions.
3.2. The Micronaut Application
Now, let’s create the service layer of our Micronaut application:
@Singleton
public class ArithmeticService {
// implementation identical to the Spring Boot service layer
}
Next, we’ll write our REST controller with the same four endpoints as the Spring Boot applications:
@Controller("/math")
public class ArithmeticController {
@Inject
private ArithmeticService arithmeticService;
@Get("/sum/{number1}/{number2}")
public float getSum(float number1, float number2) {
return arithmeticService.add(number1, number2);
}
@Get("/subtract/{number1}/{number2}")
public float getDifference(float number1, float number2) {
return arithmeticService.subtract(number1, number2);
}
@Get("/multiply/{number1}/{number2}")
public float getMultiplication(float number1, float number2) {
return arithmeticService.multiply(number1, number2);
}
@Get("/divide/{number1}/{number2}")
public float getDivision(float number1, float number2) {
return arithmeticService.divide(number1, number2);
}
}
We can see a lot of similarities between our very simple example applications. In terms of differences, we see that Micronaut takes advantage of Java’s annotations for injection whereas Spring Boot has its own. Additionally, our Micronaut REST endpoints don’t require any special annotations on the path variables passed into the methods.
3.3. Basic Performance Comparison
Micronaut advertises fast start-up times, so let’s compare our two applications.
First, let’s fire up the Spring Boot application and see how long it takes:
[main] INFO c.b.m.v.s.CompareApplication - Started CompareApplication in 3.179 seconds (JVM running for 4.164)
Next, let’s see how quickly our Micronaut application starts:
21:22:49.267 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 1278ms. Server Running: http://localhost:57535
We can see that our Spring Boot application starts up in just over three seconds and a little over one second in Micronaut.
Now that we’ve looked at start-up time, let’s exercise our APIs a bit and then check some basic memory statistics. We’ll use the default memory settings when we start our applications.
We’ll start with the Spring Boot application. First, let’s call each of the four arithmetic endpoints and then pull our memory endpoint:
Initial: 0.25 GB
Used: 0.02 GB
Max: 4.00 GB
Committed: 0.06 GB
Next, let’s run through the same exercise with our Micronaut application:
Initial: 0.25 GB
Used: 0.01 GB
Max: 4.00 GB
Committed: 0.03 GB
In this limited example, both our applications use little memory, but the Micronaut uses about half as much as the Spring Boot application.
4. Comparison
There is no single “best” framework for all applications. The best choice will depend on the specific requirements of the application and the preferences of the developers.
However, the following table can provide some information that may be helpful in making a decision:
Features
Micronaut
Spring Boot
Size
Smaller JAR files
Larger JAR Files
Actuator
No support
Yes, which provides health checks, metrics, and more
Build time
Faster
Slower
Startup time
Faster build time
Slower build time
Performance
Much better than Spring boot
OK
Native image
Yes
No default support
Auto Configuration
Less
More
Starter dependencies
Fewer starter dependencies
More starter dependencies
Dependency injection
Annotation-based
Property-based
Community
Smaller community
Larger community
Documentation
Good documentation
Excellent documentation
5. Conclusion
In this article, we compared Spring Boot with Micronaut. First, we started with an overview of what the two frameworks are. Then, we went through several features and compared the options. Finally, we pitted two simple example applications against each other. We took a look at the code for both applications and then looked at start-up and memory performance.
As always, the example code is available over on GitHub for both the Spring Boot and the Micronaut application.