一、简介
上一节微服务之间调用是使用RestTemplate调用的,使用这种方法我们必须拼接字符串的方式构造URL
@GetMapping("/hello/{name}")
public String demo1(@PathVariable("name") String name){
return this.restTemplate.getForObject("http://localhost:7100/hello/"+name,String.class);
}
当请求参数过多URL拼接的形式将十分麻烦,而且在使用POST、DELETE、PUT更加复杂,且难以维护。
Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。
在Spring Cloud中,使用Feign非常简单——创建一个接口,并在接口上添加一些注解,代码就完成了。Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。
Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。
Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这两者的强大功能外,还提供了一种声明式的Web服务客户端定义的方式。
Spring Cloud Feign帮助我们定义和实现依赖服务接口的定义。在Spring Cloud feign的实现下,只需要创建一个接口并用注解方式配置它,即可完成服务提供方的接口绑定,简化了在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发量。
Spring Cloud Feign具备可插拔的注解支持,支持Feign注解、JAX-RS注解和Spring MVC的注解。
二、为微服务消费者整合Feign
1、复制项目eureka-client-consumer为eureka-client-consumer-feign
2、添加Feign依赖
pom.xml如下
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
3、为main类添加@EnableFeignClients注解
package com.springclouddemo.eurekaclientconsumerfeign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author 何昌杰
*/
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class EurekaClientConsumerFeignApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientConsumerFeignApplication.class, args);
}
}
4、将application配置文件修改如下:
spring.application.name=eureka-client-consumer-feign
server.port=7204
eureka.client.service-url.defaultZone=http://localhost:7000/eureka/
eureka.instance.prefer-ip-address=true
5、创建一个Feign接口
(feign/ProviderFeign.java),并添加FeignClient注解
package com.springclouddemo.eurekaclientconsumerfeign.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @author 何昌杰
*/
@Component
@FeignClient(name = "eureka-client-provider")
public interface ProviderFeign {
@GetMapping("/hello/{name}")
String demo1(@PathVariable("name") String name);
}
- @Feign注解中的name是任意微服务的名称,用于创建Ribbon负载均衡器,这里会将eureka-client-provider解析为Eureka Server服务注册表的服务。
- @Feign注解的方式,集成了Ribbon实现负载均衡
- Feign接口中的方法必须与eureka-client-provider所提供的方法的请求类型一致,若为动态路径含有@PathVariable必须写路径参数名
6、将DemoController修改如下:
package com.springclouddemo.eurekaclientconsumerfeign.controllers;
import com.springclouddemo.eurekaclientconsumerfeign.feign.ProviderFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* @author 何昌杰
*/
@RestController
public class DemoController {
@Autowired
private ProviderFeign providerFeign;
@GetMapping("/hello/{name}")
public String demo1(@PathVariable("name") String name){
return providerFeign.demo1(name);
}
}
7、启动main类
这样我们就可以使用Feign调用微服务的API了。
Eureka Server 首页如图:
访问http://localhost:7204/hello/hcj,结果如下:
以上说明我们实现了声明式REST API调用,同事实现了微服务消费的负载均衡
三、Feign多参数请求
本节讲述如何使用Feign构造多参数的请求,以GET、POST请求为例。
1、GET请求多参数URL
当一个GET请求,携带多个请求参数时,后端接口可以使用@RequestParam注解标识变量来进行参数接收,可以是一个属性对应一个变量的写法也可以使用一个Map来接收请求参数。以下就是错误写法和正确写法:
错误写法:
@GetMapping("/select")
User getUser(@RequestParam User user);
正确写法1:
@GetMapping("/select")
User getUser(@RequestParam("id") Long id, @RequestParam("name") String name, @RequestParam("age") Integer age);
正确写法2:
@GetMapping("/select")
User getUser(@RequestParam Map<String,Object> params);
2、POST请求多参数
假设微服务提供者eureka-client-provider包含某一POST请求接口如下:
@RestController
public class UserController {
@PostMapping("/insert")
public int postMethod(@RequestBody User user){
//...
}
//...
}
那么微服务消费者的Feign接口如下:
/**
* @author 何昌杰
*/
@Component
@FeignClient(name = "eureka-client-provider")
public interface ProviderFeign {
@PostMapping("/insert")
int postMethod(@RequestBody User user);
}
四、自定义Feign配置
Feign的默认配置类是FeignClientsConfiguration,该类定义了Feign默认使用的解码器,编码器,契约,日志输出,拦截器等等。
Feign允许通过@FeignClient的configuration属性自定义Feign配置,该方式优先级高于FeignClientsConfiguration。
1、复制项目eureka-client-consumer-feign为eureka-client-consumer-feign-configuration
2、创建Fein配置
创建config/FeignConfiguration.java
package com.springclouddemo.eurekaclientconsumerfeinconfiguraton.config;
import feign.Contract;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author 何昌杰
*/
@Configuration
public class FeignConfiguration {
/**
* 将契约修改为Feign原生契约
* @return Contract
*/
@Bean
public Contract feignContract(){
return new Contract.Default();
}
/**
* 配置Logger.Level的日志记录等级
* @return Level
*/
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
Logger.Level值有以下几种:
- NONE 不记录任何日志(默认值)
- BASIC 仅记录请求方法、URL、响应状态码和执行时间
- HEADERS 记录BASIC级别的基础上,记录请求和响应的Header
- FULL 记录请求和响应的Header,body,元数据
3、将ProviderFeign.java修改如下
package com.springclouddemo.eurekaclientconsumerfeinconfiguraton.feign;
import com.springclouddemo.eurekaclientconsumerfeinconfiguraton.config.FeignConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* @author 何昌杰
*/
@Component
@FeignClient(name = "eureka-client-provider",configuration = FeignConfiguration.class)
public interface ProviderFeign {
@RequestMapping(value = "/hello/{name}",method = RequestMethod.GET)
String demo1(@PathVariable("name") String name);
}
4、将application配置文件修改如下:
spring.application.name=eureka-client-consumer-feign-configuration
server.port=7205
eureka.client.service-url.defaultZone=http://localhost:7000/eureka/
eureka.instance.prefer-ip-address=true
logging.level.com.springclouddemo.eurekaclientconsumerfeinconfiguraton.feign.ProviderFeign=debug
5、启动main类
五、Feign继承
Feign支持继承,使用继承将一些公共操作分组放到一些父接口中,从而简化Feign的开发,
基础接口:UserFeign.java
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
String selectOneById(@PathVariable("id") String id);
服务消费者:ConsumerFeign.java
@FeignClient(name = "eureka-client-provider")
public interface ConsumerFeign extends UserFeign {
//...
}
六、Feign压缩
Feign开启压缩功能后,可对请求、响应进行压缩,能有效节约网络资源,但是会增加CPU压力,通过以下属性启动Feign压缩:
feign.compression.request.enabled=true
feign.compression.response.enabled=true
对于请求的压缩,Feign还提供了一些配置
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048