Why Spring Boot 4.1.1 Makes Controllers and JSON Unnecessary for Internal Microservice Calls
Spring Boot 4.1.1 now offers native gRPC support, letting Java microservices replace the usual REST controllers, DTOs, Feign clients and JSON payloads with a single .proto definition, generated code, and built‑in security, health, observability and testing features, while highlighting best practices and pitfalls.
1. The problem with REST glue code
In a typical Java microservice, an order service calls an inventory service via a REST controller, DTOs, a Feign client and JSON serialization. This creates a lot of boilerplate and a fragile contract that can break when field names change.
@RestController
@RequestMapping("/internal/inventory")
public class InventoryController {
@GetMapping("/{skuId}")
public InventoryResponse query(@PathVariable Long skuId) {
return inventoryService.query(skuId);
}
} public record InventoryResponse(Long skuId, Integer availableStock, Boolean saleable) {} @FeignClient(name = "inventory-service")
public interface InventoryClient {
@GetMapping("/internal/inventory/{skuId}")
InventoryResponse query(@PathVariable Long skuId);
}The stack involves Controller → DTO → Feign Client → JSON → HTTP, and any mismatch between versions can cause compatibility issues.
2. gRPC starts with a .proto file
Spring Boot 4.1 expects .proto files under src/main/proto. The Protobuf plugin generates Java and gRPC stubs automatically.
syntax = "proto3";
package inventory;
option java_package = "com.example.inventory.grpc";
option java_multiple_files = true;
service InventoryService {
rpc QueryInventory(InventoryRequest) returns (InventoryReply);
}
message InventoryRequest { int64 sku_id = 1; }
message InventoryReply {
int64 sku_id = 1;
int32 available_stock = 2;
bool saleable = 3;
}After compilation, Java classes such as InventoryRequest, InventoryReply and InventoryServiceGrpc are generated, eliminating the need for @GetMapping, @RequestBody, and JSON handling.
3. Server implementation without a controller
Add the starter dependency:
org.springframework.boot:spring-boot-starter-grpc-serverImplement the generated abstract base class:
@GrpcService
public class InventoryGrpcService extends InventoryServiceGrpc.InventoryServiceImplBase {
private final InventoryService inventoryService;
public InventoryGrpcService(InventoryService inventoryService) {
this.inventoryService = inventoryService;
}
@Override
public void queryInventory(InventoryRequest request, StreamObserver<InventoryReply> responseObserver) {
Inventory inventory = inventoryService.query(request.getSkuId());
InventoryReply reply = InventoryReply.newBuilder()
.setSkuId(inventory.getSkuId())
.setAvailableStock(inventory.getStock())
.setSaleable(inventory.isSaleable())
.build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}The flow changes from Controller → JSON → HTTP Response to GrpcService → Protobuf Object → RPC Response. Spring Boot automatically discovers beans that implement BindableService and exposes them as gRPC services.
4. Client side – no manual HTTP construction
Add the client starter:
org.springframework.boot:spring-boot-starter-grpc-clientImport the generated stub:
@SpringBootApplication
@ImportGrpcClients(target = "inventory", types = {InventoryServiceGrpc.InventoryServiceBlockingStub.class})
public class OrderApplication {}Configure the channel:
spring:
grpc:
client:
channel:
inventory:
target: static://inventory-service:9090Use the stub in business code:
@Service
public class OrderInventoryClient {
private final InventoryServiceGrpc.InventoryServiceBlockingStub inventoryStub;
public OrderInventoryClient(InventoryServiceGrpc.InventoryServiceBlockingStub inventoryStub) {
this.inventoryStub = inventoryStub;
}
public int queryStock(long skuId) {
InventoryRequest request = InventoryRequest.newBuilder().setSkuId(skuId).build();
InventoryReply reply = inventoryStub.queryInventory(request);
return reply.getAvailableStock();
}
}The call looks like a local Java method invocation.
5. Compile‑time safety with Protobuf
If a field is renamed or removed, the generated Java code will no longer compile, exposing contract violations early. The article warns against reusing field numbers for unrelated fields and recommends version‑controlled .proto schemas.
6. Deadlines prevent cascading failures
gRPC does not set a sensible deadline by default. Adding a 300 ms deadline avoids indefinite waits that could cause thread exhaustion and system‑wide avalanches.
InventoryReply reply = inventoryStub
.withDeadlineAfter(300, TimeUnit.MILLISECONDS)
.queryInventory(request);Setting a deadline at each hop ensures that a stalled downstream service does not block the entire call chain.
7. Streaming beyond unary RPC
gRPC natively supports client, server and bidirectional streaming, which is useful for real‑time order status, logs, AI results, IoT data, file transfer, etc., avoiding the need for polling loops.
8. Full‑stack support in Spring Boot 4.1
The new release bundles security, health checks, Micrometer observability and test utilities for gRPC. Example test annotations:
@SpringBootTest
@AutoConfigureTestGrpcTransport
class InventoryGrpcTest {}In‑process transport removes the need for a real network port during tests.
9. Migration strategy
External APIs remain REST/JSON for browser and third‑party compatibility, while internal service‑to‑service communication can gradually move to gRPC.
Browser/App → REST/JSON → API Gateway → order‑service
order‑service → (gRPC) → inventory‑service / payment‑serviceThis hybrid approach balances ease of debugging, ecosystem maturity, and the compile‑time safety of gRPC for internal calls.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
LuTiao Programming
LuTiao Programming is a friendly community offering free programming lessons. We inspire learners to explore new ideas and technologies and quickly acquire job-ready skills.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
