)
OpenFeign 是 Spring Cloud 提供的声明式、模板化 HTTP 客户端可像调用本地方法一样调用远程微服务内置 Ribbon 负载均衡、支持熔断降级 / 日志 / 拦截器等以下从环境搭建、基础使用、进阶配置、实战场景全流程详解。一、环境准备Spring Cloud Alibaba Nacos1. 项目结构2 个微服务服务提供者user-service提供用户查询 / 新增接口端口 8081服务消费者order-service通过 Feign 调用 user-service端口 8082注册中心Nacos默认端口 88482. 依赖引入消费者 / 提供者通用父工程 pom.xml统一版本管理xmlparent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.14/version relativePath/ /parent properties spring-cloud.version2021.0.8/spring-cloud.version spring-cloud-alibaba.version2021.0.5.0/spring-cloud-alibaba.version /properties dependencyManagement dependencies !-- Spring Cloud 依赖 -- dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-dependencies/artifactId version${spring-cloud.version}/version typepom/type scopeimport/scope /dependency !-- Spring Cloud Alibaba 依赖 -- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-alibaba-dependencies/artifactId version${spring-cloud-alibaba.version}/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement消费者order-servicepom.xml核心 Feign 依赖xmldependencies !-- Spring Web -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- OpenFeign 核心依赖 -- dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-openfeign/artifactId /dependency !-- Nacos 服务注册/发现 -- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency !-- 熔断降级Sentinel可选 -- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-sentinel/artifactId /dependency !-- 日志/测试依赖省略 -- /dependencies3. 配置文件application.yml服务提供者user-service8081yamlserver: port: 8081 spring: application: name: user-service # 服务名Feign 调用核心标识 cloud: nacos: discovery: server-addr: 127.0.0.1:8848 # Nacos 地址服务消费者order-service8082yamlserver: port: 8082 spring: application: name: order-service cloud: nacos: discovery: server-addr: 127.0.0.1:8848 sentinel: transport: dashboard: 127.0.0.1:8080 # Sentinel 控制台可选 # Feign 全局配置可选 feign: client: config: default: # default 代表全局也可指定服务名如 user-service connectTimeout: 5000 # 连接超时ms readTimeout: 10000 # 读取超时ms loggerLevel: FULL # 日志级别NONE/BASIC/HEADERS/FULL sentinel: enabled: true # 开启 Feign 整合 Sentinel熔断降级二、基础使用核心三步步骤 1服务提供者编写接口user-service1. 实体类 UserDTOjava运行import lombok.Data; Data public class UserDTO { private Long id; private String username; private Integer age; }2. Controller 接口对外提供 HTTP 服务java运行import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; RestController RequestMapping(/user) public class UserController { // 模拟数据库 private static final MapLong, UserDTO USER_MAP new HashMap(); static { UserDTO user new UserDTO(); user.setId(1L); user.setUsername(zhangsan); user.setAge(20); USER_MAP.put(1L, user); } // GET根据ID查询用户 GetMapping(/{id}) public UserDTO getUserById(PathVariable Long id) { return USER_MAP.get(id); } // GET多参数查询 GetMapping(/search) public UserDTO searchUser(RequestParam String username, RequestParam Integer age) { return USER_MAP.values().stream() .filter(u - u.getUsername().equals(username) u.getAge().equals(age)) .findFirst().orElse(null); } // POST新增用户 PostMapping public UserDTO createUser(RequestBody UserDTO user) { USER_MAP.put(user.getId(), user); return user; } // PUT更新用户 PutMapping(/{id}) public UserDTO updateUser(PathVariable Long id, RequestBody UserDTO user) { user.setId(id); USER_MAP.put(id, user); return user; } // DELETE删除用户 DeleteMapping(/{id}) public String deleteUser(PathVariable Long id) { USER_MAP.remove(id); return 删除成功ID id; } }步骤 2消费者定义 Feign 客户端核心1. 启动类开启 Feign 功能java运行import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; SpringBootApplication EnableFeignClients // 必须加扫描 FeignClient 注解生成代理类 public class OrderServiceApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class, args); } }2. 编写 Feign 客户端接口与提供者 Controller 一一对应java运行import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.*; // FeignClient声明 Feign 客户端name 指定目标服务名与提供者 spring.application.name 一致 FeignClient(name user-service) public interface UserFeignClient { // GET路径参数PathVariable 必须指定 value否则报错 GetMapping(/user/{id}) UserDTO getUserById(PathVariable(id) Long id); // GET多请求参数RequestParam 可省略 value参数名一致即可 GetMapping(/user/search) UserDTO searchUser(RequestParam String username, RequestParam Integer age); // POST请求体RequestBody 必须加否则参数无法传递 PostMapping(/user) UserDTO createUser(RequestBody UserDTO user); // PUT路径参数 请求体 PutMapping(/user/{id}) UserDTO updateUser(PathVariable(id) Long id, RequestBody UserDTO user); // DELETE路径参数 DeleteMapping(/user/{id}) String deleteUser(PathVariable(id) Long id); }步骤 3消费者业务代码调用 Feign1. Service 层注入 Feign 客户端java运行import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; Service public class OrderService { Autowired private UserFeignClient userFeignClient; // 注入 Feign 客户端 // 调用用户服务查询用户 public UserDTO getUser(Long id) { return userFeignClient.getUserById(id); } // 调用用户服务新增用户 public UserDTO createUser(UserDTO user) { return userFeignClient.createUser(user); } // 调用用户服务更新用户 public UserDTO updateUser(Long id, UserDTO user) { return userFeignClient.updateUser(id, user); } // 调用用户服务删除用户 public String deleteUser(Long id) { return userFeignClient.deleteUser(id); } }2. Controller 层对外提供接口java运行import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; RestController RequestMapping(/order) public class OrderController { Autowired private OrderService orderService; GetMapping(/user/{id}) public UserDTO getUser(PathVariable Long id) { return orderService.getUser(id); } PostMapping(/user) public UserDTO createUser(RequestBody UserDTO user) { return orderService.createUser(user); } PutMapping(/user/{id}) public UserDTO updateUser(PathVariable Long id, RequestBody UserDTO user) { return orderService.updateUser(id, user); } DeleteMapping(/user/{id}) public String deleteUser(PathVariable Long id) { return orderService.deleteUser(id); } }三、进阶配置实战必备1. Feign 日志配置调试必备1. 全局日志配置application.ymlyamlfeign: client: config: default: loggerLevel: FULL # 日志级别NONE(无)、BASIC(请求行)、HEADERS(请求行头)、FULL(全部) # 开启 Feign 日志级别必须加否则日志不打印 logging: level: # Feign 客户端接口所在包改为你的实际包名 com.order.feign: debug2. 局部日志配置针对单个服务yamlfeign: client: config: user-service: # 服务名仅对该服务生效 loggerLevel: HEADERS2. 超时配置避免请求阻塞全局超时application.ymlyamlfeign: client: config: default: connectTimeout: 5000 # 连接超时5秒 readTimeout: 10000 # 读取超时10秒局部超时针对单个服务yamlfeign: client: config: user-service: connectTimeout: 3000 readTimeout: 50003. 自定义拦截器统一添加请求头 / 参数场景所有 Feign 请求自动添加 Tokenjava运行import feign.RequestInterceptor; import feign.RequestTemplate; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class FeignInterceptorConfig { Bean public RequestInterceptor requestInterceptor() { return new RequestInterceptor() { Override public void apply(RequestTemplate template) { // 1. 添加请求头如 Token template.header(Authorization, Bearer xxx-token-xxx); // 2. 添加公共请求参数 template.query(source, order-service); } }; } }4. 熔断降级Sentinel 整合服务容错1. 编写 Fallback 降级类服务异常时执行java运行import org.springframework.stereotype.Component; Component public class UserFeignFallback implements UserFeignClient { Override public UserDTO getUserById(Long id) { // 降级逻辑返回默认用户 UserDTO defaultUser new UserDTO(); defaultUser.setId(-1L); defaultUser.setUsername(默认用户); defaultUser.setAge(0); return defaultUser; } Override public UserDTO searchUser(String username, Integer age) { return getUserById(-1L); } Override public UserDTO createUser(UserDTO user) { return getUserById(-1L); } Override public UserDTO updateUser(Long id, UserDTO user) { return getUserById(-1L); } Override public String deleteUser(Long id) { return 服务降级删除用户失败; } }2. Feign 客户端绑定 Fallbackjava运行// fallback 指定降级类fallbackFactory 可获取异常信息二选一 FeignClient(name user-service, fallback UserFeignFallback.class) public interface UserFeignClient { // 接口方法不变 }3. FallbackFactory获取异常精准降级java运行import feign.hystrix.FallbackFactory; import org.springframework.stereotype.Component; Component public class UserFeignFallbackFactory implements FallbackFactoryUserFeignClient { Override public UserFeignClient create(Throwable cause) { return new UserFeignClient() { Override public UserDTO getUserById(Long id) { // 打印异常信息便于排查 System.out.println(调用用户服务异常 cause.getMessage()); UserDTO defaultUser new UserDTO(); defaultUser.setId(-1L); defaultUser.setUsername(服务异常 cause.getMessage()); return defaultUser; } // 其他方法降级逻辑省略 }; } }java运行// Feign 客户端绑定 FallbackFactory FeignClient(name user-service, fallbackFactory UserFeignFallbackFactory.class) public interface UserFeignClient { // 接口方法不变 }5. 直连调用跳过注册中心调试 / 对接第三方场景本地调试、对接第三方 API不注册到 Nacosjava运行// url 指定直连地址name 必须填语法要求 FeignClient(name user-service-debug, url http://127.0.0.1:8081) public interface UserDebugFeignClient { // 接口方法与 UserFeignClient 一致 GetMapping(/user/{id}) UserDTO getUserById(PathVariable(id) Long id); }6. 复杂参数传递Map / 对象 / 文件1. GET 请求传递 Map 参数java运行GetMapping(/user/list) ListUserDTO listUser(RequestParam MapString, Object params);2. 多对象参数必须加 RequestParam 或 SpringQueryMapjava运行// 方式1RequestParam 拆分 GetMapping(/user/query) UserDTO queryUser(RequestParam Long id, RequestParam String username); // 方式2SpringQueryMapSpring Cloud 提供支持对象转 GET 参数 GetMapping(/user/query) UserDTO queryUser(SpringQueryMap UserDTO user);3. 文件上传Feign 支持 MultipartFile1. 引入文件上传依赖xmldependency groupIdio.github.openfeign.form/groupId artifactIdfeign-form/artifactId version3.8.0/version /dependency dependency groupIdio.github.openfeign.form/groupId artifactIdfeign-form-spring/artifactId version3.8.0/version /dependency2. Feign 客户端文件上传接口java运行import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.multipart.MultipartFile; FeignClient(name user-service) public interface FileFeignClient { // consumes 指定 multipart/form-data PostMapping(value /user/upload, consumes MediaType.MULTIPART_FORM_DATA_VALUE) String uploadFile(RequestPart(file) MultipartFile file); }四、启动与测试启动 Nacos 服务访问 http://127.0.0.1:8848启动 user-service8081、order-service8082测试接口Postman 调用 order-service 接口查询用户GET http://127.0.0.1:8082/order/user/1新增用户POST http://127.0.0.1:8082/order/userBody 传 JSON更新用户PUT http://127.0.0.1:8082/order/user/1删除用户DELETE http://127.0.0.1:8082/order/user/1五、常见问题与坑PathVariable 报错必须指定 value如 PathVariable (id)Feign 无法识别无 value 的路径参数GET 请求对象参数为空GET 不支持 RequestBody需用 SpringQueryMap 或 RequestParam 拆分请求头丢失Feign 默认不传递请求头需自定义 RequestInterceptor 手动添加超时不生效检查配置文件中 feign.client.config 的层级确保服务名 /default 配置正确熔断降级不生效需开启 feign.sentinel.enabled: true且 Fallback 类需加 Component