一、简介
- 在Ribbon介绍了通过
RestTemplate实现远程调用的方法。但是该方法没那么方便,不符合程序员的使用习惯。 OpenFeign采用了接口调用的方法,非常符合程序员的习惯,远程调用方法就像本地调用一样方便。- 官网
Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单。- 它的使用方法是定义一个服务接口然后在上面添加注解。
Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡 - 简单来说,就是Feign封装了Ribbon,将对象使用封装成了接口调用,在使用的时候通过动态代理的方式实现该接口,然后再调用。
二、实验
1. 导包
<dependencies>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--一般基础通用配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. yaml配置文件
- 值得一提的是,它关闭了自己在注册中心的注册,其他机器是无法发现它们的。
server:
port: 80
eureka:
client:
# 直接关闭自己的注册
register-with-eureka: false
service-url:
defaultZone: http://127.0.0.1:7001/eureka/,http://127.0.0.1:7002/eureka/
3. 主启动类
@SpringBootApplication
@EnableFeignClients // 开启Feign
public class OrderFeignMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderFeignMain80.class, args);
}
}
4. 业务类
- 这是远程服务器真实的请求处理方法
@RestController
public class PaymentController {
@PostMapping("/payment/create")
CommonResult<Object> create(@RequestBody Payment payment) {
// 省略
}
@ApiOperation("查找payment")
@GetMapping("/payment/get/{id}")
CommonResult<Payment> selectById(@PathVariable("id") Long id) {
// 省略
}
}
- 为了远程调用这些方法,需要自己写一个接口。在接口上标一个注解
@FeignClient表示这是一个远程调用的接口,并且给出远程调用服务的名称,该名称与在注册中心上注册的服务名相同。接口上面的注解、方法、参数与原来的基本上没什么太大区别。
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface FeignPaymentService {
@PostMapping("/payment/create")
CommonResult<Object> create(@RequestBody Payment payment);
@GetMapping("/payment/get/{id}")
CommonResult<Payment> selectById(@PathVariable("id") Long id);
}
注意:RequestMapping不能RPC调用!!!一定要指定GetMapping/PostMapping之类的
- 调用接口。调用接口的时候就像调用本地对象一样方便了。
@Slf4j
@RestController
@RequestMapping("/feign")
public class OrderController {
@Autowired
FeignPaymentService feignPaymentService; // 将远程调用接口注入
@GetMapping("/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
CommonResult<Payment> result = feignPaymentService.selectById(id); // 直接调用并获取结果
log.info("查询 id: " + id + "的结果为:" + result.toString());
return result;
}
@PostMapping("/payment/create")
public CommonResult createPayment(@RequestBody Payment payment) {
CommonResult<Object> result = feignPaymentService.create(payment);
log.info("插入数据:" + payment.toString());
return result;
}
}
5. 负载均衡
- 自动开启了负载均衡。实际上还是Ribbon的负载均衡,默认还是轮询方式的负载均衡策略。修改策略也和Ribbon的一样。在配置文件中进行修改。
CLOUD-PAYMENT-SERVICE: # 服务名
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 策略
三、超时控制
- 除了简单的远程调用之外,Feign还支持超时控制。Feign默认超时等待1s,如果超过了超时时间,就会触发异常,放弃等待。
1. 修改超时时间
- 可以通过配置文件修改默认的超时时间
#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000
四、日志打印功能
- 可以通过日志打印,监控远程调用的一些信息
1. 配置日志级别
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
- NONE:默认的,不显示任何日志;
- BASIC:仅记录请求方法、URL、响应状态码及执行时间;
- HEADERS:除了 BASIC 中定义的信息之外,还有请求和响应的头信息;
- FULL:除了 HEADERS 中定义的信息之外,还有请求和响应的正文及元数据。
2. 修改配置文件
- 还需要修改Spring Boot的日志级别,开启该接口的日志级别为debug
logging:
level:
# feign日志以什么级别监控哪个接口
com.atguigu.springcloud.service.PaymentFeignService: debug
3. 查看日志
- 在控制台,可以看到日志输出
2021-05-23 17:28:33.303 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService : [FeignPaymentService#selectById] ---> GET http://CLOUD-PAYMENT-SERVICE/payment/get/1 HTTP/1.1
2021-05-23 17:28:33.303 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService : [FeignPaymentService#selectById] ---> END HTTP (0-byte body)
2021-05-23 17:28:33.314 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService : [FeignPaymentService#selectById] <--- HTTP/1.1 200 (10ms)
2021-05-23 17:28:33.314 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService : [FeignPaymentService#selectById] connection: keep-alive
2021-05-23 17:28:33.314 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService : [FeignPaymentService#selectById] content-type: application/json
2021-05-23 17:28:33.314 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService : [FeignPaymentService#selectById] date: Sun, 23 May 2021 09:28:33 GMT
2021-05-23 17:28:33.314 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService : [FeignPaymentService#selectById] keep-alive: timeout=60
2021-05-23 17:28:33.315 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService : [FeignPaymentService#selectById] transfer-encoding: chunked
2021-05-23 17:28:33.315 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService : [FeignPaymentService#selectById]
2021-05-23 17:28:33.316 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService : [FeignPaymentService#selectById] {"code":200,"message":"查询Payment 1 成功!, Port: 8001","data":{"id":1,"serial":"48193048109341"}}
2021-05-23 17:28:33.316 DEBUG 22968 --- [p-nio-80-exec-1] l.d.s.service.FeignPaymentService : [FeignPaymentService#selectById] <--- END HTTP (104-byte body)
2021-05-23 17:28:33.320 INFO 22968 --- [p-nio-80-exec-1] l.d.s.controller.OrderController : 查询 id: 1的结果为:CommonResult(code=200, message=查询Payment 1 成功!, Port: 8001, data=Payment(id=1, serial=48193048109341))