1基础
1.1Feign概述
●Feign是一 个声明式的REST客户端,它用了基于接口的注解方式,很方便实现客户端配置。
●Feign最初由Netlix公司提供,但不支持SpringMVC注解,后由SpringCloud对其封装,支持了SpringMVC注解,让使用者更易于接受。
1.2Feign快速入门
demo 目录结构
1.2.1.在消费端(consumer)引入open-feign依赖
consumer的pom添加依赖
<!-- 添加Feign 引用 start 由于netflix 版本不支持 springmvc ;所以要使用open版本-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 添加Feign 引用 end-->
1.2.1补充【open-feign】完整引用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
1.2.2.编写Feign调用接口(使用服务名作为调用依据)
/**
* 1.定义接口!
* 2.接口上添加注解@FeignClient,设置value属性为服务提供者的应用名称
* 3.编写调用接口,接口的声明规则和提供方接口保持一致。
* 4.注入该接口对象,调用接口方法完成远程调用
* backend-show-provider 是provider的名称
*/
@FeignClient(value = "backend-show-provider")
public interface ConsumerApp {
/**
* provider Controller名称;sayhello 请求的方法名
*
* @param message
* @return
*/
@GetMapping("/provider/sayhello2")
String providerSayHello2(@RequestParam("message")String message);
}
1.2.3.在启动类添加@EnableFeignClients注解,开启Feign功能
consumer的application.java中添加
@SpringBootApplication
@EnableFeignClients //开启Feign的功能
public class BackendShowConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(BackendShowConsumerApplication.class,args);
}
}
1.2.4.测试调用
consumer服务中
@Resource
private ConsumerApp consumerApp;
@GetMapping(value = "/sayhello2")
public String sayhello2(String message){
String result = null;
try {
result = consumerApp.providerSayHello2(message);
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
provider服务代码
@GetMapping("/sayhello2")
public String providerSayHello2(String message,String username) {
System.out.println("username:"+username);
// int a=1/0;//错误
try {
Thread.sleep(2000);//超时设置
} catch (InterruptedException e) {
e.printStackTrace();
}
log.error("provder sayhello port:{}, message:{}", port, message);
return "Provider sayhello port:" + port + " , message:" + message;
}
1.2.5.特别注意
编写Feign调用接口时候,注意方法的参数必须 @RequestParam (例如:@RequestParam("message")String message) 否则 【status 405 reading】
1.2.6 openFeign另一种写法(使用端口号)
不推荐使用这种,在实际发布情况中,可能存在端口被暂用。需要改端口的情况
/**
* name 名称,可以自己随意取;url 对应的服务请求地址
*/
@FeignClient(name="providerTest",url = "http://localhost:7010")
public interface ConsumerApp {
/**
* provider Controller名称;sayhello 请求的方法名
*
* @param message
* @return
*/
@GetMapping("/provider/sayhello2")
String providerSayHello2(@RequestParam("message")String message);
}
2Feign超时设置
- Feign底层依赖于Ribbon实现负载均衡和远程调用。
- Feign就是对Ribbon进行一次封装,Ribbon有的Feign也有。
- 一般给Feign设置超时时间就是设置Ribbon的
- Ribbon默认1秒超时。
- Feign超时设置都是在调用放(consumer)设置(applicaation.yml中)
ribbon:
ConnectTimeout: 2000 # Ribbon的连接超时时间
ReadTimeout: 3000 # Ribbon的数据读取超时时间
OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
MaxAutoRetries: 1 # 对当前实例的重试次数
3Feign日志打印
- Feign只能记录debug级别的日志信息。所以需要在application.yml中设置日志的级别
logging:
level:
com.item.backed: debug #com.item.backed为包名,也可具体指定哪个class
- 定义Feign日志级别Bean (格式固定)
package com.item.backed.consumer.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignLogConfig {
/**
* NONE ,不记录
* BASIC,记录基本的请求行,响应状态码数据
* HEADERS,记录基本的请求行,响应状态码数据,记录响应头信息
* FULL ;记录完成的请求响应数据
* @return
*/
@Bean
public Logger.Level level(){
return Logger.Level.FULL;
}
}
- 启用该Bean:
,configuration = FeignLogConfig.class
最后查看日志
3补充
3.1Fegin支持多种http调用形式
Feign支持多种http调用形式(这里网上说不支持@GetMapping和@POSTMapping,但是本次的demo都是用的这两个,却可以运行通。) 如果使用以上两种形式请求,报错【Request method 'POST' not supported】。可以尝试更换
3.2FeginClient相关参数详解
3.2.1path
前面demo中两种@FeignClient写法都只用到两个参数(configuration、value 或者 name和url);去请求另外一个服务的Controller 路径都写在请求的方法上面。例如:
@GetMapping("/provider/sayhello2")
String providerSayHello2(@RequestParam("message")String message);
现在,在@FeginClinet中添加一个参数 path就行:
import com.item.backed.consumer.config.FeignLogConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = "backend-show-provider",path = "/provider",configuration = FeignLogConfig.class)
public interface ConsumerApp {
/**
* provider Controller名称;sayhello 请求的方法名
*
* @param message
* @return
*/
@GetMapping("/sayhello2")
String providerSayHello2(@RequestParam("message")String message);
}
请求如下
3.2.2configuration 自定义Fegin配置
配置类型 | 默认配置 |
feignDecoder | ResponseEntityDecoder |
feignEncoder | SpringEncoder |
feignLogger | SIf4jLogger |
feignContract | SpringMvcContract |
feignBuilder | HystrixFeign.Builder |
feignClient | LoadBalancerFeignClient或者feignClient |
3.3Feign实战技巧
Feign继承
◆微服务的目标是大量复用, Feign会导致重复工作量
◆Feign提供了继承特性帮助我们解决这个问题
接口复用最多只能有一层,切忌多继承
3.4Feign多组件集成
◆Feign可以集成Ribbon实现负载均衡
◆Feign可以集成Hystrix实现命令封装
◆Feign可以集成Hystrix实现业务降级
Feign之HTTP性能优化
◆Feign默认使用的JDK自带的HTTP方式
◆Feign最大的优化点是更换HTTP底层实现
◆目前Apache HTTPClient是一个非常好的选择