在前一章介绍了Ribbon的用法,在使用Ribbon是通过RestTemplate调用其他服务的API时,所有参数必须在请求的URL中进行拼接。如果参数过多,拼接请求字符串会导致效率下降。Spring Cloud提供另外一种调用API的解决方案,既使用Spring Cloud Feign。
Feign是一种负载均衡的HTTP客户端,它封装了Ribbon。使用Feign调用API就像调用本地方法一样。从而避免了调用微服务时,需要不断封装/解析Json数据的繁琐步骤。
Feign是一个声明似的Web客户端,它使得编写Web服务客户端变得更容易。使用Fegin创建一个接口并对它进行注解。它具有可插拔的注解支持包含Fegin注解与JAX-RS注解,Feign还支持可插拔的编码器与解码器,Spirng Cloud增加了对Spring MVC的注解功能。Feign默认集成了Ribbon,所以Fegin默认就实现了负载均衡效果。
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
@MapperScan("com.goyeer")
@SpringBootApplication
@EnableFeignClients
public class GoyeerApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
@FeignClient("orderservice")
public interface OrderClient {
@GetMapping("/Order/findById")
Order findById(@PathVariable("orderId") Long orderId);
}
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependency>
<groupId>io.github.openfeigngroupId>
<artifactId>feign-jacksonartifactId>
<version>9.7.0version>
dependency>
@RequestLine("GET /user/getone?arkOrgId={arkOrgId}&userId={userId}")
JSONObject getOneEmployee(@Param("orgId") String orgId,@Param("userId") String userId);
@RequestLine("POST /user/add")
@Headers("Content-Type: application/json")
@Body("{body}")
JSONObject saveEmployee(@Param("body") EmployeeDTO employeeDTO);
public class App{
public static void main(String[] args){
EmloyeeAPI emloyeeAPI = Feign.builder().target(EmloyeeAPI.class,"http://localhost:8088");
String result = emloyeeAPI.getOneEmployee("110","1110");
System.out.println(result);
}
}
| 注解 | 类型 | 说明 |
|---|---|---|
| @RequestLine | Method | 定义其请求方法和请求路径(UriTemplate)。请求路径以斜杠开始,中间可以使用{变量名称},表达式的值由@Param注解提供。 |
| @Param | Parameter | 定义变量模板,可通过表达式{变量名称}引用变量的值 |
| @Headers | Method,Type | 定义请求头,可以使用{变量名},表达式的值由@Param注解提供。 |
| @QueryMap | Parameter | 定义Map或者Pojo类型参数。 |
| @HeaderMap | Parameter | 定义Map类型的请求头 |
| @Body | Method | 对@Param扩展,配合@Headers使用可定义JSON、XML类型参数 |
指定接口类型和URL地址接口Http代理对象,从而通过代理对象调用方法发送HTTP请求。
Feign在默认情况下使用的是JDK原生的URLConnection发送HTTP请求。
指定连接超时时长及响应超时时长,单位毫秒。
指定重试策略,参数分别是最小时间,最大时间,重连次数。
指定编码/解码方式默认是String
指定日志和日志等级、可配置SLF4J等
用来开启Feign
标记要用Feign来拦截的请求接口
value 和 name 的作用一样,如果没有配置url那么配置的值将作为服务名称,用于服务发现。反之只是一个名称。
serviceId已经废弃了,直接使用name即可。
解决Bean的名称冲突了。
url用于配置指定服务的地址,相当于直接请求这个服务,不经过Ribbon的服务选择。像调试等场景可以使用。
当调用请求发生404错误时,decode404的值为true,那么会执行decoder解码,否则抛出异常。
configuration是配置Feign配置类,在配置类中可以自定义Feign的Encoder、Decoder、LogLevel、Contract等。
定义容错的处理类,也就是回退逻辑,fallback的类必须实现Feign Client的接口,无法知道熔断的异常信息。
也是容错的处理,可以知道熔断的异常信息。
path定义当前FeignClient访问接口时的统一前缀,比如接口地址是/user/get, 如果你定义了前缀是user, 那么具体方法上的路径就只需要写/get 即可。
primary对应的是 @Primary 注解,默认为 true,官方这样设置也是有原因的。当我们的Feign实现了fallback后,也就意味着Feign Client有多个相同的Bean在Spring容器中,当我们在使用@Autowired进行注入的时候,不知道注入哪个,所以我们需要设置一个优先级高的,@Primary 注解就是干这件事情的。
qualifier 对应的是 @Qualifier 注解,使用场景跟上面的primary关系很淡,一般场景直接 @Autowired 直接注入就可以了。
在工程中增加一个配置类、如下设定日志级别,可作为全局配置
@Configuration
public class FeignConfig{
@Bean
public Logger.Level level(){
return Logger.level.FULL;
}
}
首先将FeignConfig的@Configuration注解去掉,否则将是全局配置。
在@FeignClient中configuration属性赋值为FeignConfig.class
@FeignClient(path = "/employee", value = "provider", configuration = FeignConfig.class)
public interface UserService {
@RequestMapping("/list")
List<String> findEmployee();
}
在配置文件中,加入如下配置,provider为服务端服务名,改配置只对调用provider服务时生效。
feign.client.config.provider.loggerLevel=BASIC

Ribbon与Feign都是实现负载均衡的组件,Feign的本质是Ribbon,是基于Ribbon的实现。都是加在消费端的注解,让消费端可以调用其他生产者的服务。
RestTemplate 是从 Spring3.0 开始支持的一个 HTTP 请求工具,它提供了常见的REST请求方案的模版,例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute。RestTemplate 继承自 InterceptingHttpAccessor 并且实现了 RestOperations 接口,其中 RestOperations 接口定义了基本的 RESTful 操作,这些操作在 RestTemplate 中都得到了实现。
一种负载均衡的HTTP客户端, 使用Feign调用API就像调用本地方法一样,从避免了 调用目标微服务时,需要不断的解析/封装json 数据的繁琐。Feign是一个声明似的web服务客户端,Spring Cloud 增加了对 Spring MVC的注解,Spring Web 默认使用了HttpMessageConverters, Spring Cloud 集成 Ribbon 和 Eureka 提供的负载均衡的HTTP客户端 Feign。