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.

The Dominant Programmer
The Dominant Programmer
The Dominant Programmer
Spring MVC + OpenFeign: Contract‑First API, Controller Logic, and Feign Reuse in Microservices

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 UserFeignApi

Implementation 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-service

6. 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.

Microservice architecture diagram
Microservice architecture diagram
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavamicroservicesMavenNacosOpenFeignSpring MVCContract-First
The Dominant Programmer
Written by

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

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.