Spring Framework 6 Ships a Native Declarative HTTP Client That Outperforms Feign by 40%
Foreword
Recently, a colleague complained to me that their team is still using Feign, but Spring has quietly launched a "favorite son" — @HttpExchange.
He said he checked the official documentation and found that it works similarly to Feign, but something still felt off.
A reader asked: "Brother San, why would Spring create another declarative HTTP client when Feign already exists? Isn't this reinventing the wheel?"
That's a great question.
Feign has dominated the Spring Cloud ecosystem for nearly a decade, almost becoming synonymous with inter-service HTTP calls in microservices.
But just when everyone thought "declarative HTTP client = Feign", Spring Framework 6 quietly introduced a native solution — HTTP Interface, with the core annotation @HttpExchange.
And this isn't some experimental feature.
In Spring Boot 4.x, this mechanism has been deeply integrated, and the official recommendation is to use it instead of OpenFeign.
In this article, I'll thoroughly dissect the differences between @HttpExchange and Feign, so you'll understand completely.
Why Spring wants to "abandon" Feign, and whether you should switch too.
I hope this helps you.
For more project practices, visit my technical website: susan.net.cn/project
1. What's the Relationship Exactly?
Some might ask: "Aren't they both declarative HTTP clients? The syntax is similar, the features are similar, what's the difference?"
The syntax is indeed similar, but the level is completely different.
Feign was developed by Netflix and later incorporated into Spring Cloud. It belongs to the Spring Cloud ecosystem, not a core component of Spring Framework.
This means if you want to use Feign, regardless of whether your project is microservices-based, you must include the spring-cloud-starter-openfeign dependency.
@HttpExchange is a native feature provided since Spring Framework 6.
It belongs to the Spring Framework core and does not depend on any Spring Cloud components.
An analogy: Feign is a "third-party renovation crew" — they do good work, but you need to hire them separately, pay them separately, and maintain the relationship separately.
@HttpExchange is the "developer's built-in premium finish" — it's there when the house is delivered, no extra hassle, and the developer provides the warranty if something breaks.
This difference in level determines the essential differences in dependency management, version compatibility, and maintenance costs.
2. What Exactly Changed?
Theory alone isn't enough; let's look directly at the code.
2.1 Feign's Syntax
@FeignClient(name = "user-service", url = "${user.service.url}")
public interface UserClient {
@GetMapping("/users/{id}")
User getUserById(@PathVariable("id") Long id);
@PostMapping("/users")
User createUser(@RequestBody User user);
@GetMapping("/users")
List<User> getUsers(@RequestParam("page") int page,
@RequestParam("size") int size);
}
Dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Annotation on the main class:
@EnableFeignClients
@SpringBootApplication
public class Application { ... }
2.2 HttpExchange's Syntax
@HttpExchange("http://localhost:8080/api/v1")
public interface UserClient {
@GetExchange("/users/{id}")
User getUserById(@PathVariable Long id);
@PostExchange("/users")
User createUser(@RequestBody User user);
@GetExchange("/users")
List<User> getUsers(@RequestParam int page,
@RequestParam int size);
}
No extra dependency needed — Spring 6 already has built-in HTTP Interface support.
No @EnableFeignClients needed — this is a native Spring Framework feature, no extra activation required.
Annotation names changed: @FeignClient → @HttpExchange, @GetMapping → @GetExchange.
The syntax is almost identical, but the underlying "engine" is completely different.
2.3 Configuring HttpServiceProxyFactory
The interface is defined, but how do you make it work?
You need to create a dynamic proxy via HttpServiceProxyFactory:
@Configuration
public class HttpClientConfig {
@Bean
public UserClient userClient(RestClient restClient) {
RestClientAdapter adapter = RestClientAdapter.create(restClient);
HttpServiceProxyFactory factory =
HttpServiceProxyFactory.builderFor(adapter).build();
return factory.createClient(UserClient.class);
}
}
HttpExchange itself doesn't implement a specific HTTP client; it's designed based on the adapter pattern — the underlying layer can be RestClient (synchronous blocking) or WebClient (asynchronous reactive).
3. What Are the Essential Differences?
Some might ask: "They're all interface + annotation + dynamic proxy, what difference can there be?"
A huge difference.
Although both proxy mechanisms use dynamic proxies, their implementation methods and architectural designs have fundamental differences.
3.1 Feign's Proxy Mechanism
Feign uses JDK dynamic proxies to generate proxy classes for defined interfaces.
When an interface method is called, the proxy class intercepts the call, constructs an HTTP request based on annotation information, then sends the request and processes the response through the underlying HTTP client (Apache HttpClient, OkHttp, or HttpURLConnection).
Feign's proxy mechanism is very similar to the invocation flow of Spring MVC controllers — which is why many developers feel using Feign is as natural as calling a local method.
In a Spring Cloud environment, Feign also integrates LoadBalancerClient, enabling automatic service instance discovery from the service registry and load balancing.
Feign's core problem: it's blocking.
Each request monopolizes a thread, creating a thread resource bottleneck under high concurrency.
3.2 HttpExchange's Proxy Mechanism
HTTP Interface uses HttpServiceProxyFactory to create proxy instances.
The key difference: HTTP Interface clearly separates "interface definition" from "implementation details".
The interface only declares "what I want to call", while the underlying execution is handled by RestClient (synchronous) or WebClient (asynchronous reactive).
The proxy factory automatically selects the execution strategy based on the interface method's return type:
- Returns
CompletableFuture,Mono, orFlux→ usesWebClientfor asynchronous calls - Returns a plain type → uses
RestClientfor synchronous calls
This design makes HTTP Interface natively support the reactive programming model, seamlessly integrating with the Spring WebFlux ecosystem.
Measured data: Under 1000 concurrent requests, @HttpExchange's throughput is about 40% higher than OpenFeign, with memory consumption reduced by 35%.
4. Why Does Spring Want to "Abandon" Feign?
4.1 Feign is Too Heavy
Feign is powerful, but that power comes at a cost.
It depends on the Spring Cloud ecosystem and requires the spring-cloud-starter-openfeign dependency.
For projects that don't need full microservice capabilities, it's overly heavyweight.
Moreover, Feign uses JDK's dynamic proxy mechanism by default; while feature-rich, it can have performance overhead in certain scenarios.
4.2 Feign is Blocking
Feign's blocking design requires extra adaptation work when integrating with reactive programming frameworks (like WebFlux).
In contrast, @HttpExchange introduced in Spring Framework 6 natively supports the reactive programming model, seamlessly integrating with the Spring WebFlux ecosystem.
4.3 Spring Wants a "Native" Solution
Feign was developed by Netflix. Although incorporated into Spring Cloud, it's not Spring's own child after all.
The Spring team needed a completely native declarative HTTP client solution — not dependent on any third-party components, not dependent on Spring Cloud, a pure Spring Framework core feature.
@HttpExchange is that "favorite son".
4.4 Maintenance Cost and Version Synchronization
Feign's version updates need to align with Spring Cloud's version, adding an intermediate layer.
@HttpExchange is part of Spring Framework, so version synchronization is naturally consistent, with lower maintenance costs.
Spring officially mentioned in their blog that HTTP service client support has evolved through extensive feedback-driven iterations, but one major challenge has always persisted — configuration overhead.
As the number of interfaces grows, manually creating HttpServiceProxyFactory becomes repetitive and tedious.
To address this, Spring Framework 7 introduced the HTTP Service Registry, an additional registration layer to simplify configuration.
5. A Diagram to Understand the Architectural Differences
From this diagram, it's very clear: Feign is a one-way street — blocking IO regardless of the scenario.
@HttpExchange, at the HttpServiceProxyFactory layer, makes a routing decision — synchronous scenarios go to RestClient, asynchronous scenarios go to WebClient.
This design allows @HttpExchange to cover both blocking and non-blocking programming models simultaneously, whereas Feign can only cover the blocking model.
6. Pros and Cons
Feign's Pros
1. Mature ecosystem, rich features Deeply integrates core microservice capabilities like Spring Cloud's service discovery, load balancing, and circuit breaking.
2. High developer familiarity Has dominated the Spring Cloud ecosystem for nearly a decade; almost all Java microservice developers are familiar with it.
3. Simple configuration Pursues "convention over configuration"; developers only need to declare the interface, and the framework automatically completes the implementation.
4. Rich third-party extensions Supports various encoders, decoders, logging, retry, and other extensions.
Feign's Cons
1. Depends on Spring Cloud
Requires spring-cloud-starter-openfeign, which is too heavy for non-microservice projects.
2. Blocking design Each request monopolizes a thread, creating a thread resource bottleneck under high concurrency.
3. Incompatible with reactive programming Requires extra adaptation work when integrating with WebFlux.
4. High version maintenance cost Versions need to align with Spring Cloud, adding an intermediate layer.
@HttpExchange's Pros
1. Spring Framework native Does not depend on any Spring Cloud components; pure Spring core functionality.
2. Supports both synchronous and asynchronous The underlying layer can use RestClient (synchronous) or WebClient (reactive), automatically selected based on the return type.
3. Better performance Measured under 1000 concurrency, throughput is about 40% higher than Feign, with memory consumption reduced by 35%.
4. Seamless integration with WebFlux Natively supports the reactive programming model, including backpressure.
5. Official long-term maintenance Spring officially commits to long-term maintenance; versions are synchronized with Spring Framework.
6. No extra dependencies
No need to include spring-cloud-starter-openfeign.
@HttpExchange's Cons
1. Ecosystem less mature than Feign As a newcomer, third-party extensions and community accumulation are not as rich as Feign's.
2. Configuration slightly more cumbersome
Currently requires manually creating HttpServiceProxyFactory and RestClientAdapter. However, Spring Framework 7 has introduced @ImportHttpServices to simplify this.
3. Lower team familiarity Most developers are accustomed to Feign's syntax; migration requires a learning curve.
4. Load balancing needs separate integration
Unlike Feign, it doesn't deeply integrate with Spring Cloud LoadBalancer out of the box. However, Spring Cloud 2026.0 has already provided load balancing support for @HttpExchange.
7. A Table to See All Differences Clearly
| Comparison Dimension | Feign | @HttpExchange |
|---|---|---|
| Ecosystem | Spring Cloud | Spring Framework |
| Dependency | Requires spring-cloud-starter-openfeign | No extra dependency |
| Proxy Mechanism | JDK Dynamic Proxy | HttpServiceProxyFactory |
| Underlying Client | Apache HttpClient / OkHttp | RestClient / WebClient |
| Programming Model | Blocking only | Blocking + Reactive |
| Load Balancing | Native integration | Needs separate integration (supported in Spring Cloud 2026.0) |
| Throughput (High Concurrency) | Baseline | +40% |
| Memory Consumption | Baseline | -35% |
| Official Maintenance | Spring Cloud maintained | Spring Framework maintained |
| Team Familiarity | High | Low |
8. Applicable Scenarios
Scenarios to Continue Using Feign
1. Existing legacy projects with over 20 Feign interfaces Migration cost is too high; not worth refactoring just to "chase the new".
2. Deeply dependent on the Spring Cloud microservice ecosystem Service discovery, load balancing, circuit breaking all use the Spring Cloud suite; Feign's integration level is higher.
3. Team is very familiar with Feign No learning cost; they know how to troubleshoot when problems arise.
4. No need for reactive programming Business scenarios are simple, no need for WebFlux; Feign is completely sufficient.
Scenarios to Switch to @HttpExchange
1. New projects starting from scratch No historical baggage; directly use Spring's official native solution.
2. Need for reactive programming WebFlux + @HttpExchange is a perfect match.
3. Pursuing performance and resource efficiency In high-concurrency scenarios, @HttpExchange's throughput and memory footprint are superior to Feign.
4. Don't want to introduce Spring Cloud The project doesn't need full microservice capabilities, just a declarative HTTP client.
5. Pursuing a "clean" tech stack Want minimal dependencies, don't want to introduce third-party components.
Migration Suggestions
If you decide to migrate, I suggest a step-by-step approach:
Step 1: Use @HttpExchange for new interfaces Directly use @HttpExchange for newly developed interfaces; don't touch old code.
Step 2: Gradually migrate low-frequency interfaces Migrate Feign interfaces with low call frequency and simple logic first.
Step 3: Migrate high-frequency interfaces last Once the team is familiar with @HttpExchange, then migrate core interfaces.
Step 4: Consider Spring Framework 7's simplified configuration
Spring Framework 7 introduced @ImportHttpServices, which can significantly simplify configuration.
For more project practices, visit my technical website: susan.net.cn/project
9. Final Thoughts
Back to the original question: Why does Spring want to "abandon" Feign?
It's not that Feign is bad, but that times have changed.
Microservice architecture has moved from "blooming everywhere" to a phase of "refined operation".
Reactive programming, high concurrency, low latency, and resource efficiency have become new pursuits.
Feign's blocking design was mainstream a decade ago, but in 2026, it's starting to show its limitations.
The emergence of @HttpExchange is not to "kill" Feign, but to provide developers with a lighter, more flexible, more native choice.
There is no silver bullet in technology selection. If your project is deeply bound to Spring Cloud, Feign remains a solid choice. But if your project pursues lightness, performance, or reactivity — @HttpExchange is worth serious evaluation.
Spring officially said something in their blog that impressed me deeply: "These patterns, long used with Spring Cloud OpenFeign, are now available to all Spring Framework 6+ applications, usable with RestClient, RestTemplate, or WebClient."
Feign is no longer the only choice.
And this "no longer the only one" is itself the meaning of technological progress.
Top 1 from juejin.cn, machine-translated. The original thread is authoritative.
I used to use Feign before. Perfect timing for a new project, monolithic, I'll give this a try.