引入
基于之前的学习,我们目前调用是通过restTemplate硬编码方式调用的。
restTemplate.getForObject("http://stock-service/stock/reduce", String.class);
还是很不方便,考虑直接用service.方法进行调用,从而引出Feign,实现接口的远程调用。
Java项目中常见的接口调用有:httpClient、okhttp、httpURLConnection、RestTemplate、webClient。
其次还有Feign的远程调用。
一、什么是Feign?
Feign是NetFlix开发的声明式、模板化的HTTP客户端。
spring Cloud OpenFeign对Feign进行了增强,使其支持spring MVC注解,另外还整合了Ribbon和nacos,从而使得Feign的使用更加方便。
所以我们都是使用openFeign。
Ribbon、Nacos、Feign三个结合使用是我们入门必学。
优势:Feign可以做到使用HTTP请求远程服务像调用本地方法一样的体验。
二、spring Cloud Alibaba整合openfeign
项目结构:
1、引入依赖
<!--添加openfeign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、写一个FeignService接口—feign.StockFeignService
/**
* name : 指定调用接口的服务名
* path : 指定调用接口所在的controller指定的@RequestMapping
*/
@FeignClient(name = "stock-service",path = "/stock")
public interface StockFeignService {
//声明需要调用的接口对应的方法,即对应着远程接口的方法,和本地service一样的模式。
@RequestMapping("/reduce")
public String reduce();
}
//此处是对应库存的接口,和上面openfeign的service进行一个对比
//
//@RestController
//@RequestMapping("/stock")
//public class StockController {
//
// @Value("${server.port}")
// private String port;
//
// @RequestMapping("reduce")
// public String reduce(){
// System.out.println("扣减库存");
// return "扣减库存:"+port;
// }
//}
其他说明:
远程接口项目结构如图,之前nacos篇讲过,其实就是一个sprign could服务。
3、使用stockFeignService调用远程的接口,注入调用接口
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private StockFeignService stockFeignService;
@RequestMapping("/add")
public String add(){
System.out.println("新增订单");
String reduce = stockFeignService.reduce();
return "openFeign远程调用:"+reduce;
}
}
}
4、需再启动类上加上@EnableFeignClients注解。
@SpringBootApplication
@EnableFeignClients
public class OrderOpenFeignApplication{
public static void main(String[] args) {
SpringApplication.run(OrderOpenFeignApplication.class,args);
}
}
5、测试
三、openFeign日志配置
Feign 提供了很多的扩展机制,让用户可以更加灵活的使用。
有时候我们遇到 Bug,比如接口调用失败、参数没收到等问题,或者想看看调用性能,就需要配置 Feign 的日志了,以此让 Feign 把请求信息输出来。
日志配置有两种全局配置和局部配置
1、全局配置
(1)定义一个配置类,指定日志级别
/**
* @Description:
* 全局配置 当使用@Configuration 会将配置作用在所有的服务提供方
* 局部配置 如果只想针对某个服务进行配置,就不要加 @Configuration
* @Date: 2023/5/8 23:56
*/
@Configuration
public class FeignConfig {
//Logger使用import feign.Logger;
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
通过源码可以看到日志等级有 4 种,分别是:
- NONE[性能最佳,适用于生产]: 不记录任何日志 (默认值) 。
- BASIC[适用于生产环境追踪问题]:仅记录请求方法、URL、响应状态代码以及执行时间。
- HEADERS: 记录BASIC级别的基础上,记录请求和响应的header。
- FULL[比较适用于开发及测试环境定位问题]: 记录请求和响应的header、 body和元数据。
(2)修改配置文件Feign中service的日志输出级别
#springboot 默认的日志级别是info ,feign 的debug日志就不会输入
#重新修改一下feign下的servicer日志级别
logging:
level:
com:
tc:
order:
feign: debug
(3)调用接口http://localhost:8830/order/add测试。
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private StockFeignService stockFeignService;
@Autowired
private ProductFeignService productFeignService;
@RequestMapping("/add")
public String add(){
System.out.println("新增订单");
String reduce = stockFeignService.reduce();
String product = productFeignService.get(1);
return "openFeign远程调用:"+reduce + "---"+product;
}
}
日志输出:
2、局部配置,让调用的微服务生效
方法一:在@FeignClient 注解中指定使用的配置类。
(1)去除上面1(1)中FeignConfig配置类中的@Configuration注解。
(2)在对应的FeignService中的@FeignClient 注解中指定使用的配置类。
例如在ProductFeignService加入configuration = FeignConfig.class指定日志级别的配置类。
@FeignClient(name = "product-service",path = "/product",configuration = FeignConfig.class)
public interface ProductFeignService {
@RequestMapping("/{id}")
public String get(@PathVariable("id") Integer id);
}
方法二:配置文件配置。单个服务的日志建议使用配置文件的方式。
#springboot 默认的日志级别是info ,feign 的debug日志就不会输入
#重新修改一下feign下的servicer日志级别
logging:
level:
com:
tc:
order:
feign: debug
#Feign 日志局部配置
feign:
client:
config:
stock-service: #服务名
loggerLevel: BASIC
四、openFeign契约配置
spring cloud 在 Feign 的基础上做了扩展,使用spring mvc的注解来完成Feign的功能,原生的Feign是不支持spring MVC 注解的,如果想在spring cloud中使用原生的注解方式来定于客户端也是可以的,通过契约来改变这个配置,Spring Cloud 中默认的是SpringMvcContract。
Spring Cloud 1 早期版本就是用的原生Fegin.随着netflix的停更替换成了Open feign。
配置文件配置契约,也可以写Bean配置类(用不到,不学了);
1、配置contract
#Feign 日志局部配置
feign:
client:
config:
stock-service: #服务名
loggerLevel: BASIC
contract: feign.Contract.Default #设置为默认的契约,还原成原生的注解
2、修改接口注解
@FeignClient(name = "stock-service",path = "/stock")
public interface StockFeignService {
//声明需要调用的接口对应的方法
//@RequestMapping("/reduce")
//Feign 的原生注解
@RequestLine(" GET /reduce")
public String reduce();
}
五、openFeign超时时间配置
可以配置类配置全局配置和配置文件指定服务配置。
方法一:配置类配置
通过 Optons 可以配置连接超时时间和读超时间,Optns 的第一个参数是连接的超时时间ms),默值是 2s;第二个是求处理的超时时间ms,默认值是5s。
@Configuration
public class FeignConfig {
@Bean
public Request.Options options(){
return new Request.Options(5000,1000);
}
}
方法二:配置文件配置
#Feign 日志局部配置
feign:
client:
config:
stock-service: #服务名
loggerLevel: BASIC
contract: feign.Contract.Default #设置为默认的契约,还原成原生的注解
#连接超时时间 默认2s
connectTimeOut: 5000
#请求处理超时时间 默认5s
readTimeOut: 3000
六、openFeign自定义拦截器
自定义拦截器实现认证逻辑。
调用的时候,进行拦截在请求头写入参数等。
/**
* @Description: Feign 拦截器
* @Date: 2023/5/9 0:58
*/
public class FeignInterceptor implements RequestInterceptor {
public void apply(RequestTemplate requestTemplate) {
//todo
System.out.println("Feign 拦截器。自行写逻辑");
}
}
如何让拦截器生效
方法一:配置类
@Configuration
public class FeignConfig {
//Logger使用import feign.Logger; 自定义日志
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
//自定义拦截器
@Bean
public FeignInterceptor feignInterceptor(){
return new FeignInterceptor();
}
}
方法二:配置类配置。
#Feign 日志局部配置
feign:
client:
config:
stock-service: #服务名
loggerLevel: BASIC
contract: feign.Contract.Default #设置为默认的契约,还原成原生的注解
#连接超时时间 默认2s
connectTimeOut: 5000
#请求处理超时时间 默认5s
readTimeOut: 3000
#自定义拦截器
requestInterceptors[0]: com.tc.order.interceptor.FeignInterceptor
拦截日志: