在SpringCloud系列之Ribbon一文中我们介绍了使用RestTemplate配合Ribbon实现服务的调用和客户端负载均衡。但是使用RestTemplate调用服务有个弊端,就是参数传递不方便,无论是GET还是POST,都需要对参数进行组装,一旦参数比较多,实际开发时将非常麻烦,而且容易出错。所以,本文将介绍另一种Spring Cloud的服务调用方式——Feign。
Feign
Feign也是Netflix开发的,它是一种声明式、模版化的HTTP客户端,相对于RestTemplate更加便捷、优雅。在Spring Cloud中,我们可以使用Feign非常方便的创建服务调用的模版代码,配合相关的注解,完成配置。
实战
修改provider-user服务
增加测试接口
增加新增用户
和设置用户name
接口,其他都不需要修改
package com.huluohu.cloud.user.presentation.web;
import com.huluohu.cloud.user.presentation.mode.UserDTO; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*;
import java.util.Random;
@Slf4j @RestController @RequestMapping("/user") public class UserController { private Random random = new Random();
@GetMapping("/{id}") public UserDTO findById(@PathVariable Integer id) { return UserDTO.builder() .id(id) .username("root_" + id) .name("huluohu_" + id) .age(random.nextInt(30) % (30 - 15 + 1) + 15) .balance(random.nextLong()) .build(); }
@PostMapping() public Integer add(UserDTO user) { return random.nextInt(); }
@PutMapping("/{id}") public Boolean setName(@PathVariable Integer id, @RequestParam("name") String name){ log.info("id={}", id); log.info("name={}", name); return Boolean.TRUE; } }
|
创建Feign测试工程
consuer-movie-feign
复制consuer-movie module
,修改名称为consuer-movie-feign

新增依赖
在pom.xml下增加Feign的依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency>
|
修改启动类
package com.huluohu.cloud.movie;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.feign.EnableFeignClients;
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients(basePackages = "com.huluohu.cloud.movie.application.client") public class MovieApplication { public static void main(String[] args) { SpringApplication.run(MovieApplication.class,args); } }
|
增加服务调用代码
package com.huluohu.cloud.movie.application.client;
import com.huluohu.cloud.movie.application.model.User; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.*;
@FeignClient(serviceId = "provider-user") public interface UserServiceClient {
@RequestMapping(value = "/user/{id}", method = RequestMethod.GET) User findById(@PathVariable("id") Integer id);
@RequestMapping(value = "/user", method = RequestMethod.POST) Integer addUser(@RequestBody User user);
@RequestMapping(value = "/user/{id}", method = RequestMethod.PUT) Boolean setName(@PathVariable("id") Integer id, @RequestParam("name") String name); }
|
增加测试代码
package com.huluohu.cloud.movie.presentation.web;
import com.huluohu.cloud.movie.application.client.UserServiceClient; import com.huluohu.cloud.movie.application.model.User; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController @RequestMapping("/test") public class TestController { @Resource private UserServiceClient userServiceClient;
@GetMapping("/user/{id}") public Object testFindUser(@PathVariable Integer id) { final User user = userServiceClient.findById(id); return ResponseEntity.ok(user); }
@PostMapping("/user") public Object testAddUser(User user) { return ResponseEntity.ok(userServiceClient.addUser(user)); }
@PutMapping("/user/{id}") public Object testSetName(@PathVariable Integer id, @RequestParam("name") String name) { return ResponseEntity.ok(userServiceClient.setName(id, name)); } }
|
配置
配置文件和consumer-movie中的一样。
到此,准备工作都已经完成了,下面开始测试。
测试
- 启动Eureka Server(local profile)
- 启动Config Server(不需要区分profile)
- 启动provider-user(local profile)
- 启动provider-user(local2 profile,模拟多节点)
- 启动consumer-movie-feign(local profile)
启动应用列表

服务注册情况

测试结果(使用Postman测试)
以上三个测试,分别测试三种参数传递的情况:
- 查询用户,测试通过
GET
方式,使用@PathVariable
注解从请求URL中获取参数 - 新增用户,测试通过
POST
方式,使用@RequestBody
注解传递多个参数的情况 - 设置用户name,测试通过
PUT
方式,使用@RequestParam
传递单个参数的情况
进阶
在Spring Cloud中,支持对Feign进行自定义配置,包括编码器、解码器、契约、拦截器等进行自定义:
- Decoder
- Encoder
- Logger
- Contract
- Feign.Builder
- Client
还有一些Bean在Spring Cloud中没有提供默认的实现,但是如果在应用上下文中存在这些实现,也会被Feign应用:
- Logger.Level
- Retryer
- ErrorDecoder
- Request.Options
- Collection
- SetterFactory
如果需要自定义以上Bean,可以创建一个Configuration类,然后设置到FeignClient即可:
配置类
@Configuration public class UserServiceConfiguration { @Bean public Contract feignContract() { return new feign.Contract.Default(); }
@Bean public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { return new BasicAuthRequestInterceptor("user", "password"); } }
|
使用配置
@FeignClient(name = "provider-user", configuration = UserServiceConfiguration.class) public interface UserServiceClient { }
|

“扫一扫接着看”