-
Notifications
You must be signed in to change notification settings - Fork 38.9k
Description
Type: Enhancement
With the increasing service-ification of infrastructure (e.g., SaaS, DBaaS, STaaS) and the widespread adoption of microservices exposing capabilities via gRPC/Protobuf or HTTP/REST, invoking services by logical name—whether inside or outside the cluster—has become a natural and widely accepted pattern.
The service provider inherently owns the most authoritative contract: a Java interface with annotations.
Ideally, consumers should be able to:
- Reuse that exact interface directly,
- Invoke methods using only a logical service name (e.g.,
"user-service"), - Enjoy local-method-like syntax without worrying about protocols, serialization, service discovery, or networking details.
This ideal centers on two core principles:
✅ Interface as Contract
✅ Service Name as Target
However, the current Spring Boot ecosystem lacks native support for this paradigm:
| Protocol | Current Solution | Gap vs. Ideal Paradigm |
|---|---|---|
| HTTP | RestTemplate / WebClient |
Manual URI/method/error handling; no interface reuse |
| HTTP | @HttpExchange + WebClient |
Supports interfaces but requires explicit proxy creation |
| HTTP | @ImportHttpServices |
Groups clients by service—closer to the ideal |
| HTTP | OpenFeign | Widely used, but forces consumers to duplicate interface definitions, violating "single source of truth" |
| gRPC | @ImportGrpcClients |
Similar to @ImportHttpServices, but protocol-specific |
Despite protocol differences, all scenarios point to the same need:
Let providers publish a Java interface; let consumers inject it via
@ServiceClient("service-name")—no extra config, no duplication.
✨ Ideal usage example:
// Interface published by user-service (e.g., via shared library)
public interface UserClient {
@GetMapping("/users/{id}")
User getUser(@PathVariable String id);
}
// Consumer simply injects by logical service name
@Service
public class OrderService {
@ServiceClient("user-service") // ← Resolved to actual endpoint automatically
private final UserClient userClient;
public void processOrder() {
User user = userClient.getUser("123"); // Transparent remote call
}
}This pattern has already proven valuable in several ecosystems:
- gRPC:
grpc-springenables interface reuse and service-name binding via@GrpcClient("service-name"). - OpenFeign: Though it requires interface duplication, it demonstrates strong demand for declarative service clients.
I've built a working prototype (see #https://github.com/seal90/service-client-spring/).
Proposal
Could Spring Boot provide an official, lightweight, declarative service client abstraction (e.g., @ServiceClient) that supports the “interface reuse + service-name-as-target” paradigm?
It should offer:
- Contract Reuse: Use the provider's published Java interface directly—no duplication.
- Service-Name Driven: Resolve endpoints by logical name (e.g.,
"payment-service") and integrate with Spring Cloud LoadBalancer. - Protocol Agnostic: Start with HTTP support; extensible to gRPC, RSocket, etc.
- Zero-Config Experience: Seamlessly integrate with Spring Boot observability (Micrometer), health checks, config refresh, and auto-configuration.
Adopting a “single source of truth + declarative invocation” model would dramatically reduce boilerplate and cognitive load for service-to-service communication.