OpenFeign–服务调用
1、Feign与OpenFeign
? Feign英文表意为“假装,伪装,变形” ,是一个http请求调用的轻量级框架,属于NetFlix公司,和其他的NetFlix组件一样,已经宣布不再进行更新了。因此Spring社区在Feign的基础之上推出了OpenFeign, 对Feign进行增强支持Spring MVC注解,可以像Spring Web一样使用HttpMessageConverters等。 本质上来讲,二者都是完成服务调用的轻量级框架,使用方法也一致。
? 在服务消费者中使用Feign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求。
2、OpenFeign的使用
? 第一步:pom依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
? 第二步:主启动类
@SpringBootApplication
//开启Feign功能支持
@EnableFeignClients
public class OrderFeignMain80 {public static void main(String[] args) {SpringApplication.run(OrderFeignMain80.class,args);}
}
? 第三步:书写服务接口
//表示当前FeignClient消费的服务是CLOUD-PAYMENT-SERVICE(Eureka上的服务名)
@FeignClient("CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {//服务提供者暴露出来的uri路径和访问方式@GetMapping(value = "/payment/get/{id}")//服务提供者暴露出来的方法声明CommonResult getPaymentById(@PathVariable("id") Long id);
}
? 第四步:书写控制器
@RestController
public class OrderController {//自动装配服务接口@Autowiredprivate PaymentFeignService paymentFeignService;//当用户访问此路径时,调用自己的服务接口//服务接口因为使用了@FeignClient注解,所以会根据配置请求://http://CLOUD-PAYMENT-SERVICE/payment/get/{id}//因为Feign集成了Ribbon,Ribbon会做负载均衡,并且将服务名转化成真实的url地址完成调用@GetMapping("/consumer/payment/get/{id}")public CommonResult getPaymentById(@PathVariable Long id){return paymentFeignService.getPaymentById(id);}
}
3、OpenFeign与RestTemplate
? 相同点:
? 1、本质上讲,二者都是用来向服务提供者发送http请求的工具
? 2、二者本身都不具备负载均衡的能力
? 3、向服务端发送请求时都是使用的服务名而非真实ip+port
? 4、都是利用了Ribbon完成的负载均衡,地址转换等工作。
? 5、默认情况下,都是采用轮询的方式完成负载均衡
? 不同点:
? 1、OpenFeign使用的是动态代理技术,RestTemplate使用的是拦截器技术。
? 2、使用的注解不同,OpenFeign使用的是@EnableFeignClients和@FeigeClient;RestTemplate使用的是@LoadBalanced;
? 3、OpenFeign本身已经继承了NetFlix Ribbon(并非Spring Cloud Ribbon),直接就可以使用Ribbon的负载均衡功能;RestTemplate只是Spring推出的一个类库,想要使用Ribbon的负载均衡功能,必须另外引入Spring Cloud Ribbon的依赖(经常是由Eureka间接引入的)。
? 优缺点对比:
? 1、 在使用RestTemplate来调用接口服务时,需要向方法传入服务提供者的接口地址,当接口地址较多时,不太方便管理。而OpenFeign通过一个服务接口把所有要调用的接口地址集中管理起来,这是一个比较好的管理方式。
? 2、使用OpenFeign进行服务调用,我们不需要像使用RestTemplate那样关心调用哪一个方法、参数类型和返回值等问题,使用起来更加方便。
? 3、OpenFeign是面向接口的编程方式,更加符合程序员的习惯,类似于三层架构中的controller调用service。
? 所以实际开发当中,使用OpenFeign完成服务调用的场景比使用RestTemplate的场景要多得多。
4、更换Ribbon的默认负载均衡策略
? 因为OpenFeign和RestTemplate一样,都是和Ribbon搭配使用的,只不过一个采用了动态代理的方式,一个采用了拦截器的方式,最终负载均衡的工作都是交给Ribbon来做的,所以替换Ribbon默认负载均衡策略的方式也是一样的。如下:
? 默认情况下,自动装配好的RestTemplate使用的负载均衡策略是轮询,即根据服务清单,一次访问各个服务实例。而Ribbon给我们提供的负载均衡策略不止轮询这一种,还有一些其他的策略:
? 我们可以通过下面的步骤修改默认的轮询策略:
? 第一步:创建配置类MySelfRuler
@Configuration
public class MySelfRuler {@Beanpublic IRule mySelfRule(){//将默认的轮询算法替换成随机算法//此处可以使用其他官方提供的算法,也可以自定义算法return new RandomRule();}
}
? 第二步:在服务消费者主配置类上使用@RibbonClient注解
@SpringBootApplication
@EnableEurekaClient
//指明本服务是一个消费者,消费CLOUD-PAYMENT-SERVICE
//使用的配置为自定义配置MySelfRuler
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRuler.class)
public class OrderMain80 {public static void main(String[] args) {SpringApplication.run(OrderMain80.class,args);}
}
? 但是要注意的是:
? 官方给出明确警告,自定义的规则配置类不能@ComponentScan注解所在包及其子包下,否则自定义的配置类会被所有的Ribbon客户端共享,不能够起到服务特殊化定制的目的。对于单个的SpringBoot程序来讲,MySelfRuler不能放在主启动类所在包及其子包下。
5、OpenFeign的超时设置
? 默认情况下,Feign发送的请求超时时间为1s,但是我们在实际开发中,可能有一些服务本身正常的调用时间就比较长,为了防止程序报错,针对这些这些服务的消费者,我们需要修改feign默认的超时时间,因为feign默认集成了Ribbon,我们可以通过设置Ribbon的超时时间来进行Feign的超时设置。如下:
ribbon:#连接成功后读取资源的超时时间(ms)ReadTimeout: 5000#建立连接的超时时间(ms)ConnectTimeout: 5000
6、OpenFeign的日志功能
? Feign与RestTemplate不同的是,http请求详细信息封装的更深了,为了方便我们查看每一次发送的http请求信息详细信息,Feign给我们提供了日志功能。说白了就是对Feign接口的调用情况进行监控和输出。
? 日志级别:
? 指http请求信息的详细程度,分为四个等级:
? NONE:默认,不显示任何日志
? BASIC:仅记录请求方法、URL、响应状态码及执行时间
? HEADERS:除了BASIC的内容之外,还有请求和响应的头信息
? FULL:除了HEADERS的内容外,还有请求和响应的正文以及元数据。
? OpenFeign使用的是slf4j作为日志门面,日志的实现根据整个项目确定。不同的日志级别底层采用的都是debug级别的输出,只不过不同的日志级别对应的输出内容数量不同。
? 如何修改Feign的日志级别:
? 第一步:书写一个配置类,向容器中注入日志级别的bean
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FeignConfig {@BeanLogger.Level feignLoggerLevel(){//将默认的日志级别改为FULLreturn Logger.Level.FULL;}
}
? 第二步:在配置文件中指明Feign接口日志的输出级别,必须为debug,因为Feign底层使用的是debug进行的日志输出。如果不指定,将使用全局统一的日志级别。
logging:level:com.ly.springcloud.service.PaymentFeignService: debug
? 第三步:测试,使用Feign完成服务调用,控制台得到如下日志:(也可以根据日志配置,将此内容输出到配置文件中去)
[PaymentFeignService#getPaymentById] <--- HTTP/1.1 200 (291ms)
[PaymentFeignService#getPaymentById] connection: keep-alive
[PaymentFeignService#getPaymentById] content-type: application/json
[PaymentFeignService#getPaymentById] date: Fri, 31 Jul 2020 03:49:36 GMT
[PaymentFeignService#getPaymentById] keep-alive: timeout=60
[PaymentFeignService#getPaymentById] transfer-encoding: chunked
[PaymentFeignService#getPaymentById]
[PaymentFeignService#getPaymentById] {"code":200,"message":"查询成功,port: 8001","data":{"id":2,"serial":"AAAAAAAAA"}}
[PaymentFeignService#getPaymentById] <--- END HTTP (85-byte body)