By now you have probably heard of Eclipse MicroProfile (MP). It is a community-driven initiative to define specifications for enterprise Java microservices. MicroProfile is only two years old, yet it has delivered eight innovative specifications and is evolving fast. It provides metrics, API documentation, health checks, fault tolerance, distributed tracing, and more. With it, you can take full advantage of cutting-edge cloud-native technologies and do it in a vendor-neutral fashion!
For developers familiar with Spring Boot, we have prepared this article, which compares the basics of developing applications with Spring Boot and with MicroProfile. We wrote two applications, one with each solution. In this article, we will go through the differences between them. You can find the source code for both projects on GitHub.
For the MicroProfile application, we use Thorntail (formerly know as Wildfly Swarm), but except for the setting up part, Open Liberty, Payara, TomEE, or any other implementation would look exactly the same.
Throughout this article, we assume you know Spring Boot and we focus on what is different in MicroProfile.
Setting up the project
We set up both applications using Maven.
With Thorntail, the setup of a project is quite similar to Spring Boot. The first difference is in the project packaging. While we use jar
(the default packaging) for a Spring Boot app, we need to set it to war
to package a Thorntail application.
Our Spring Boot application uses a BOM file called spring-boot-dependencies
. Thorntail provides BOM files too. We selected bom
, which lists all stable, well-tested Thorntail elements. If you like to experiment, you can use bom-all
instead, for example.
Both Spring Boot and Thorntail use a Maven plugin to package user's classes, resources, and all the bits of the selected solution into a fat JAR. For Thorntail, the plugin is called thorntail-maven-plugin
. The listing below shows its declaration together with the declaration of the Thorntail BOM.
<project ...> ... <packaging>war</packaging> <dependencyManagement> <dependencies> <dependency> <groupId>io.thorntail</groupId> <artifactId>bom</artifactId> <version>${version.thorntail}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> ... <build> <plugins> <plugin> <groupId>io.thorntail</groupId> <artifactId>thorntail-maven-plugin</artifactId> <version>${version.thorntail}</version> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
Having defined the basics, we can select the features we need.
While for Spring Boot we chose spring-boot-starter-web
, we simply add a dependency on microprofile
for Thorntail.
<dependency> <groupId>io.thorntail</groupId> <artifactId>microprofile</artifactId> </dependency>
You can take a look at the final pom.xml
file in the GitHub project.
There is one more difference in setting up the project: the place where the static resources should be put. Our Spring Boot application keeps static resources in the src/main/resources/static
directory, while the Thorntail application requires them to be placed in src/main/webapp
.
Exposing a REST endpoint
The most idiomatic way to expose a REST API from a Spring application is by using Spring MVC. MicroProfile leverages JAX-RS for that purpose.
The translation from one to another is quite straightforward. Both work on annotations.
First, for JAX-RS, an Application
class is required. It extends javax.ws.rs.core.Application
and can provide a global path prefix for all JAX-RS endpoints. In our case it is:
@ApplicationPath("/api") public class ApplicationConfig extends Application { }
Then it’s just a matter of translating the resource classes annotations.
The following Spring MVC code:
@RestController @RequestMapping(value = "/api/greeting", produces = MediaType.APPLICATION_JSON_VALUE) public class GreetingController { @GetMapping public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) { ... }
translates to the following MicroProfile code:
@Path("/greeting") // 1 @Produces(MediaType.APPLICATION_JSON) // 2 public class GreetingResource { @GET // 3 public Response greeting(@QueryParam("name") @DefaultValue("World") String name) { // 4 ... }
To break it down:
- The JAX-RS endpoint class should be annotated with
@Path
. This annotation is also the place to provide any prefix for the endpoint. - A separate annotation,
@Produces
, has to be used if we want to specify the content type of the responses. It has a counterpart named@Consumes
to specify accepted request entity types. - In addition, the methods that are meant to handle the requests need to be annotated with
@GET
,@POST
,@DELETE
,@PUT
, or@HEAD
, depending on the HTTP method they are meant to handle. - Our endpoint uses a query parameter. To make it work, we used a
@RequestParam
annotation in Spring MVC. For MicroProfile, the annotation to use is@QueryParam
. To provide a default value, we added a@DefaultValue
annotation.
See the javax.ws.rs
package for other available annotations.
It is important to also mention the @Context
annotation. With it, you can inject values such as HTTP headers or security context to methods or endpoints.
Dependency injection
The core of Spring is its dependency injection. With MicroProfile, you can use CDI instead.
That mainly means using @Inject
annotation instead of Spring’s @Autowired
annotation:
@Inject private GreetingGenerator generator;
Similarly to Spring, CDI has a concept of beans and these beans live in a certain scope. The @Scope
annotation that is used to control the scope for Spring beans translates to one of the @ApplicationScoped
, @RequestScoped
, etc. CDI annotations.
Here’s an example from the GreetingGenerator
class:
@ApplicationScoped public class GreetingGenerator { … }
Check out the javax.enterprise.context
package for the list of all available options.
The translation is quite straightforward. The only catch is the fact that the default scope is different. While in Spring, the default scope is singleton, in CDI it is @Dependent
—a scope corresponding to Spring’s prototype.
Configuration
In our Spring application, we inject configuration values with the @Value
annotation.
With MicroProfile Config, we achieve the same with the following:
@Inject @ConfigProperty(name = "greeting.message") private String message;
The value for the message field above will be taken from META-INF/microprofile-config.properties
. It can be overwritten by an environment variable or a system property. MicroProfile Config also provides an easy mechanism to define a custom ConfigSource
, an additional source of configuration values.
Execution
Let’s try it all out!
To get the code, clone the GitHub repository:
git clone https://github.com/michalszynkiewicz/from-spring-to-microprofile/
The repository contains two projects in two separate directories. To build any of them, navigate to the appropriate directory and run the following:
mvn clean package
Both Spring Boot and Thorntail generate an uber-JAR. To run the Thorntail one, go into the target directory and execute this:
java -jar microprofile-from-spring-1.0-SNAPSHOT-thorntail.jar
Now, when you go to http://localhost:8080 in your browser, you should be presented with a web page exposed by the selected application. You can try out the application through the browser or access the REST API directly at http://localhost:8080/api/greeting?name=put-your-name-here.
More than a counterpart
While the code for both example applications is quite similar, the MicroProfile one has a couple more pieces of functionality.
As configured, the MicroProfile application additionally exposes:
- OpenAPI documentation for the REST endpoint, on http://localhost:8080/openapi
- Application metrics, including thread count, heap usage, etc. on http://localhost:8080/metrics
- Health checks, ready to use with Kubernetes, on http://localhost:8080/healthcheck
Moreover, without modifying the configuration, it can make use of other MicroProfile specifications, such as Fault Tolerance or a type-safe REST client.
Further reading
If you would like to learn more, you can download a free ebook: Building Microservices with Enterprise Java: A Practical Guide to Eclipse MicroProfile.
Thorntail and Eclipse Microprofile resources:
- James Falkner's article Announcing Thorntail 2.2 General Availability provides an overview of Thorntail, and how you can get started, including trying it in an online environment, no download required.
- Eclipse MicroProfile and Red Hat Update: Thorntail and SmallRye
- Eclipse MicroProfile Status in version 1.3 provides an overview of the API specifications in MicroProfile
- Cloud-native development with Eclipse Microprofile 1.2
- Thorntail project website: thorntail.io
Last updated: January 29, 2019