Spring MVC + OpenFeign: Contract‑First API, Controller Logic, and Feign Reuse in Microservices
This article explains a standard Spring MVC + OpenFeign design pattern for microservices, where a contract‑first interface defines routing and API specs, Controllers implement business logic, and Feign clients reuse the same interface for remote calls, with full Maven project setup, code samples, and Nacos integration.
Standard Spring MVC + OpenFeign Design Pattern
The article presents the most common microservice development pattern: a contract‑first interface (routing + API specification), a Controller that implements business logic, and an OpenFeign client that directly reuses the interface for remote calls. This eliminates duplicate code and guarantees contract consistency between providers and consumers.
Core Concepts
Interface layer : defines request path, HTTP method, parameters, and return type using only Spring MVC annotations; no business code.
Controller layer : implements the interface, writes real business logic, and is exposed as a REST endpoint by Spring MVC.
Feign client : extends the same interface, so URL, parameters, and method signatures are generated automatically.
Advantages
No duplicate code – provider and consumer share one API.
Contract consistency – identical URL, parameters, and return types.
Clear structure – interface defines the contract, controller focuses on business.
Easy maintenance – change the contract once and both sides are updated.
Project Structure
common-api/
└─ feign/
└─ UserFeignApi.java # core contract interface
user-service/
└─ controller/
└─ UserController.java # implements UserFeignApi
order-service/
└─ feign/
└─ UserFeignClient.java # extends UserFeignApiImplementation Steps
1. Create a parent Maven project
Use IDEA → New → Project, select Maven (no archetype), and set groupId=com.example, artifactId=spring-cloud-feign-demo, version=1.0‑SNAPSHOT. The parent pom uses spring-boot-starter-parent version 2.7.18 and imports Spring Cloud dependencies.
2. Add three modules
common-api : only the contract interface.
user-service : the provider, depends on spring-boot-starter-web and the common-api module.
order-service : the consumer, depends on spring-boot-starter-web, spring-cloud-starter-openfeign, and common-api.
3. Define the contract interface
package com.example.common;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
public interface UserApi {
@GetMapping("/api/user/{id}")
String getUserInfo(@PathVariable("id") Long id);
}4. Implement the controller in user-service
package com.example.userservice.controller;
import com.example.common.UserApi;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController implements UserApi {
@Override
public String getUserInfo(@PathVariable Long id) {
return "【用户服务】返回用户信息:id=" + id + ",姓名=张三";
}
}5. Configure service ports
server:
port: 8081
spring:
application:
name: user-service6. Create Feign client in order-service
package com.example.orderservice.feign;
import com.example.common.UserApi;
import org.springframework.cloud.openfeign.FeignClient;
@FeignClient(name = "user-service", url = "http://localhost:8081")
public interface UserFeignClient extends UserApi {
// No additional code needed
}7. Write a test controller to invoke the remote service
package com.example.orderservice.controller;
import com.example.orderservice.feign.UserFeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class OrderTestController {
@Resource
private UserFeignClient userFeignClient;
@GetMapping("/test/feign/{id}")
public String testFeign(@PathVariable Long id) {
return "【订单服务调用用户服务】
" + userFeignClient.getUserInfo(id);
}
}8. Enable Feign in the application entry
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}9. Run and test
Start user-service (port 8081) and access http://localhost:8081/api/user/100 – it returns the user info.
Start order-service (port 8082) and access http://localhost:8082/test/feign/100 – it returns the combined message from both services.
Full Upgrade to Spring Cloud + OpenFeign + Nacos
The article then shows how to replace the hard‑coded Feign URL with service discovery using Nacos. It adds the Alibaba Cloud dependencies, configures each module to register with Nacos, and changes the @FeignClient annotation to use only the service name.
Key Nacos steps
Download and start Nacos in standalone mode.
Add spring-cloud-starter-alibaba-nacos-discovery to both provider and consumer pom files.
Configure application.yml with spring.cloud.nacos.discovery.server-addr: localhost:8848.
Remove the hard‑coded URL from @FeignClient and keep name = "user-service" only.
Include spring-cloud-starter-loadbalancer because Ribbon is deprecated after Spring Cloud 2020.
Testing the Nacos‑enabled services
After starting Nacos, launch both services. The Nacos console (http://localhost:8848/nacos) shows user-service and order-service registered. Access http://localhost:8082/test/feign/100 to verify that service discovery and load balancing work correctly.
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.
The Dominant Programmer
Resources and tutorials for programmers' advanced learning journey. Advanced tracks in Java, Python, and C#. Blog: https://blog.csdn.net/badao_liumang_qizhi
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.
