Cloud Native 27 min read

Choosing a Technology Stack for Cloud‑Native Microservices: MicroProfile vs Spring

This article explains why cloud‑native microservices are beneficial, defines their key characteristics, and provides a detailed, side‑by‑side comparison of MicroProfile and Spring frameworks—including REST APIs, dependency injection, configuration, fault tolerance, security, health checks, metrics, and tracing—along with concrete code examples and starter resources.

JakartaEE China Community
JakartaEE China Community
JakartaEE China Community
Choosing a Technology Stack for Cloud‑Native Microservices: MicroProfile vs Spring

Cloud‑native microservices

A cloud‑native microservice is built to run on private, public or hybrid clouds and is designed to be elastic, stateless, externally configurable, fault‑tolerant, discoverable, secure, observable, traceable and able to report health status to the platform.

Externalized configuration – change settings without rebuilding (12‑factor principle).

Stateless RESTful services – state stored in external databases; instances are interchangeable.

Fault tolerance – continue operating when downstream services fail.

Discoverability – expose capabilities for client consumption.

Security – authenticated and authorized access per service.

Observability – emit metrics for monitoring.

Traceability – propagate correlation IDs for distributed tracing (Zipkin, Jaeger).

Cloud communication – report readiness and liveness to orchestrators such as Kubernetes.

Framework options

The two most popular stacks for building cloud‑native microservices are Eclipse MicroProfile and Spring.

MicroProfile (founded 2016 by IBM, Red Hat, Payara, Tomitribe, LJC and later joined by Microsoft and Oracle) defines a set of specifications (Config, Rest Client, Fault Tolerance, JWT, Health, Metrics, OpenTracing, etc.) implemented by runtimes such as Open Liberty, Quarkus, Payara, TomEE, Helidon and KumuluzEE.

Spring provides equivalent capabilities via Spring Boot, Spring Cloud, Spring Security, Spring Actuator, Spring Cloud Feign and Spring Cloud Sleuth.

REST API

Both stacks support JAX‑RS (MicroProfile) or Spring MVC annotations.

@ApplicationPath("/rest")
public class CatalogApplication extends Application {}

@Path("/items")
@Produces(MediaType.APPLICATION_JSON)
public class CatalogService {
    @GET
    public List<Item> getInventory() { ... }

    @GET
    @Path("{id}")
    public Response getById(@PathParam("id") long id) { ... }
}

Equivalent Spring controller:

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@RestController
public class CatalogController {
    @RequestMapping(value = "/items", method = RequestMethod.GET)
    @ResponseBody
    List<Item> getInventory() { ... }

    @RequestMapping(value = "/items/{id}", method = RequestMethod.GET)
    ResponseEntity<?> getById(@PathVariable long id) { ... }
}

Dependency injection

MicroProfile uses CDI; Spring uses its own DI/IoC.

// CDI injection
@Inject
private InventoryRefreshTask refreshTask;
// Spring injection
@Autowired
private InventoryRefreshTask refreshTask;

API documentation

MicroProfile OpenAPI automatically generates Swagger documentation from JAX‑RS resources. Example annotation:

@GET
@Produces(MediaType.APPLICATION_JSON)
@APIResponse(responseCode = "200", description = "List inventory contents.",
    content = @Content(mediaType = "application/json",
    schema = @Schema(type = SchemaType.OBJECT, implementation = InventoryList.class)))
@Operation(summary = "List inventory contents.")
public InventoryList listContents() { return manager.list(); }

Spring generates documentation via Spring REST Docs, which produces snippets from test execution.

Rest client

MicroProfile Rest Client provides a type‑safe client interface.

@Dependent
@RegisterRestClient(baseUri = "http://localhost:9080/system")
public interface InventoryServiceClient {
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    List<Item> getAllItems() throws UnknownUrlException, ServiceNotReadyException;
}

@Inject
@RestClient
private InventoryServiceClient invClient;

Spring uses @FeignClient for similar functionality.

@FeignClient(name = "inventory-service", url = "${inventoryService.url}")
public interface InventoryServiceClient {
    @RequestMapping(method = RequestMethod.GET, value = "/micro/inventory", produces = MediaType.APPLICATION_JSON_VALUE)
    List<Item> getAllItems();
}

@Autowired
private InventoryServiceClient invClient;

JSON handling

MicroProfile 2.0+ supports JSON‑B and JSON‑P.

public class Car {
    private String make;
    private String model;
    private String reg;
    // getters/setters
}

Jsonb jsonb = JsonbBuilder.create();
String json = jsonb.toJson(new Car("VW", "TGUAN", "HN19MDZ"));
Car car = jsonb.fromJson(json, Car.class);

Spring typically uses Jackson:

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(car);
Car car = mapper.readValue(json, Car.class);

Externalized configuration

MicroProfile Config reads values from system properties, environment variables or a microprofile-config.properties file.

# microprofile-config.properties
elasticsearch_url=http://es-catalog-elasticsearch:9200
elasticsearch_index=micro

Injecting the value:

@Inject @ConfigProperty(name = "elasticsearch_url") String url;

Spring achieves the same with @ConfigurationProperties:

@Component
@ConfigurationProperties(prefix = "elasticsearch")
public class ElasticsearchConfig {
    private String url;
    private String user;
    // getters/setters
}

@Autowired
private ElasticsearchConfig config;
String url = config.getUrl();

Fault tolerance

MicroProfile Fault Tolerance offers annotations such as @Timeout, @Retry, @Fallback, @Bulkhead and @CircuitBreaker.

@Timeout(value = 2, unit = ChronoUnit.SECONDS)
@Retry(maxRetries = 2, maxDuration = 2000)
@CircuitBreaker
@Fallback(fallbackMethod = "fallbackInventory")
@GET
public List<Item> getInventory() { return items; }

public List<Item> fallbackInventory() { return fallbackItemsList; }

Spring uses Netflix Hystrix (or Resilience4j) with @HystrixCommand:

@HystrixCommand(fallbackMethod = "fallback")
public List<Item> getInventory() { return items; }

public List<Item> fallback() { return fallbackItemsList; }

Security

MicroProfile JWT protects endpoints with role‑based annotations.

@DeclareRoles({"Admin", "User"})
@Path("/orders")
@RolesAllowed({"admin"})
public class OrderService {
    @Inject private JsonWebToken jwt;
    @GET @Produces(MediaType.APPLICATION_JSON)
    public InventoryList listContents() { return manager.list(); }
}

Spring Security can be enabled with @EnableWebSecurity and @EnableResourceServer to protect APIs using OAuth2/JWT.

Health checks

MicroProfile Health defines @Readiness and @Liveness endpoints ( /ready, /live) that Kubernetes probes can call.

@Readiness
public class ReadyCheck implements HealthCheck {
    public HealthCheckResponse call() { return HealthCheckResponse.up(); }
}

@Liveness
public class LiveCheck implements HealthCheck {
    public HealthCheckResponse call() { return HealthCheckResponse.up(); }
}

Spring Boot Actuator exposes /health (and sub‑paths) automatically; custom health indicators implement HealthIndicator.

Metrics

MicroProfile Metrics publishes a /metrics endpoint with built‑in counters, gauges and timers. Custom annotations such as @Timed, @Counted and @Metered can be added to methods.

@Timed(name = "Inventory.timer", absolute = true, displayName = "Inventory Timer", description = "Time taken by the Inventory", reusable = true)
@Counted(name = "Inventory", displayName = "Inventory Call count", description = "Number of times the Inventory call happened.", monotonic = true, reusable = true)
@Metered(name = "InventoryMeter", displayName = "Inventory Call Frequency", description = "Rate of the calls made to Inventory", reusable = true)
public List<Item> findAll() { ... }

Spring Actuator provides a /metrics endpoint. Custom metrics can be recorded via a CounterService or similar bean.

Distributed tracing

MicroProfile OpenTracing propagates spans across JAX‑RS calls; methods can be annotated with @Traced.

@Traced(operationName = "getCatalog.list")
public List<Item> getInventory() { ... }

Spring Cloud Sleuth automatically creates trace IDs for all requests when the dependency is on the classpath.

Getting started

MicroProfile starter – https://start.microprofile.io/ – lets you pick a runtime (Open Liberty, Helidon, Quarkus, etc.) and generate a project.

Spring Initializr – https://start.spring.io/ – generates a Spring Boot project.

Open Liberty – https://openliberty.io/ – a lightweight runtime that supports both MicroProfile and Spring.

cloud-nativemicroservicesConfigurationSpring Bootfault tolerancerestMicroProfile
JakartaEE China Community
Written by

JakartaEE China Community

JakartaEE China Community, official website: jakarta.ee/zh/community/china; gitee.com/jakarta-ee-china; space.bilibili.com/518946941; reply "Join group" to get QR code

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.