一,前言
使用RestTemplate实现Rest API调用时,我们是使用拼接字符串的方式拼接URL的,URL中如果有参数而且参数比较多,这就变得难以维护。
二,Feign简介
Feign是Netflix开发的声明式、模板化的Http客户端,其灵感来自Retrofit、JAXRS-2.0以及WebSocket。Feign可以更便捷、优雅的调用Http API
在Spring Cloud中使用Feign非常简单,创建一个接口,并在接口上添加注解就完成了。
Feign支持多种注解,Feign自带的或JAX-RS注解等。
Spring Cloud对Feign进行了增强,使Feign支持了SpringMVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。
三,为消费者整合Feign
1,添加Feign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
2,创建Feign接口,并添加@FeignClient注解
/**
Feign客户端接口
@author yebin
@date 2020/12/8 10:44
-
@since 1.0.1
*/
@FeignClient(name = "movie-provider")
public interface UserFeignClient {@RequestMapping(value = "/{id}",method = RequestMethod.GET)
public User findById(@PathVariable("id") Long id);
}
3,修改Controller及启动类
@RestController
@Slf4j
public class UserController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@Autowired //注入负载均衡客户端
private LoadBalancerClient loadBalancerClient;
@Autowired
private UserFeignClient userFeignClient;
//feign方式调用
@GetMapping("/user/feign/{id}")
public User findByIdFeign(@PathVariable Long id) {
return this.userFeignClient.findById(id);
}
//restTemplate方式调用
@GetMapping("/user/{id}")
public User findById(@PathVariable Long id) {
return this.restTemplate.getForObject("http://movie-provider:8091/" + id, User.class);
}
@GetMapping("/user/list")
public List<User> findAll() {
return restTemplate.getForObject("http://movie-provider:8091/list", List.class);
}
/**
* 获取提供者元数据信息
* @return
*/
@GetMapping("/provider/instance")
public List<ServiceInstance> getServiceInstance(){
return discoveryClient.getInstances("movie-provider");
}
/**
* 打印当前选择的是哪个节点
* 注意:
* 不能将restTemplate.getForObject()与loadBalancerClient.choose()写在一个方法中,两者会引起冲突,因为代码中restTemplate实际上
* 是一个Ribbon客户端,本身已经包含了choose行为。
*/
@GetMapping("/print-instance")
public void printInstance(){
ServiceInstance serviceInstance = loadBalancerClient.choose("movie-provider");
log.info("serviceId--->{},host--->{},port--->{}",serviceInstance.getServiceId(),serviceInstance.getHost(),serviceInstance.getPort());
}
}
/**
1,@EnableDiscoveryClient 声明这是一个Eureka Client,此处可用@EnableEurekaClient代替。
2,spring cloud 中服务发现组件有多种,如:Zookeeper,Consul等,@EnableDiscoveryClient为各种组件提供了支持。
3,@EnableDiscoveryClient是spring-cloud-commons项目的注解,是一个高度的抽象。
-
4,@EnableEurekaClient表明是Eureka 的Client,该注解是是spring-cloud-netflix项目的,只能与Eureka一起工作。
*/
@EnableDiscoveryClient
//@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients //启用Feign客户端
public class MovieConsumerFeignApplication {@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}public static void main(String[] args) {
SpringApplication.run(MovieConsumerFeignApplication.class, args);
}
}
4,自定义Feign配置
/**
Feign自定义配置类
Feign配置类不应放在与启动类同一个包下,否则该类中的配置信息就会被所有@FeignClient共享,或者显式指定
@ComponetScan不扫描@Configuration所在的包
@author yebin
@date 2020/12/8 11:06
-
@since 1.0.1
*/
@Configuration
public class FeignConfiguration {//将契约改为feign原生的契约,这样可以使用feign自带的注解了。
@Bean
public Contract feignContract(){
return new feign.Contract.Default();
}
}
5,Feign对继承的支持
Feign支持继承,可将一些公共操作抽到父接口中,以简化Feign的操作。
6,Feign对压缩的支持
一些场景下需要对请求或响应进行压缩,此时可以使用以下属性来启用Feign的压缩功能。
feign.compression.request.enable=true
feign.compression.response.enable=true
对于请求的压缩,Feign还可以更为详细的设置:
feign.compression.request.enable=true
支持的媒体类型
feign.compression.request.mime-types=text/xml,application/xml,application/json
请求的最小阈值,默认是2048
feign.compression.request.min-request-size=2048
7,Feign的日志
Feign对日志处理非常灵活,可为每个Feign客户端指定日志记录策略,每个Feign客户端都会记录一个logger。默认情况下,logger的名称是Feign接口的完事类名,需要注意的是Feign的日志只会对DEBUG级别日志做出响应。
7.1 Feign的配置类
/**
- Feign自定义配置类
- Feign配置类不应放在与启动类同一个包下,否则该类中的配置信息就会被所有@FeignClient共享,或者显式指定
- @ComponetScan不扫描@Configuration所在的包
- @author yebin
- @date 2020/12/8 11:06
- @since 1.0.1
*/
@Configuration
public class FeignConfiguration {
//Feign日志
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
8,使用Feign构造多请求的参数
Spring Cloud为Feign添加了Spring MVC注解的支持,可以使用参照Spring MVC注解的方式来构造多请求参数
GET请求:
8.1
@Configuration
public class FeignConfiguration {
@GetMapping("/get")
public User get(@RequestParam("id") Long id,@RequestParam("username") String username){
...
}
}
POST请求:
@RestController
@Slf4j
public class UserController {
@PostMapping("/post")
public User post(@RequestBody User user){
return null;
}
}