1.什么是Feign?
feign是由netfliex提供的,模板化的HTTP客户端,就是为了服务间调用而存在,但是相对于我们经常使用Resttemplate而言,resttemplate需要将我们的服务地址写死在url里面,而feign可以让服务调用者像是调用本地方法一样方便,完全感知不到服务调用的过程,而且其调用过程自带了负载均衡
而openfeign,是由spring cloud官方提供,对feign进行增强,使其支撑spring mvc注解,另外还整合了ribbon和nacos,使其对开发者而言能够更方便的使用;例如dubbo也是同样的道理
2.spring cloud alibaba整合openfeign
- 引入依赖
<!--openfeign远程服务调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 在服务调用端添加需要远程调用的openfeign方法
package com.lipengg.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @author lipengg
* @date 2023/5/21
*/
// 指定需要调用的服务的名称,name是服务名称,stock是controller最开始的@RequestMapping的地址
@FeignClient(name = "stock-service",path = "stock")
public interface StockFeignService {
/**
* stock-service的reduce()方法
*会调用stock-service中"/stock/reduce"指定的路径controller内的方法,
* @return
*/
// @GetMapping("/stock/reduce") // 如果@FeignClient中没有写path,这里就一定要写全路径
// String reduce();
// @GetMapping("/reduce/{id}") // 这里的路径和参数要和controller接口中的保持一致,如
// String reduce(@PathVariable String id);
@GetMapping("/reduce") // 这里的路径和参数要和controller接口中的保持一致
String reduce();
}
- 在服务调用端的controller接口调用第2步完成的openfeign方法
package com.lipengg.controller;
import com.lipengg.feign.StockFeignService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @author lipengg
* @date 2023/5/10
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@Resource
private StockFeignService stockFeignService;
@RequestMapping("/add")
public String add(){
String reduce = stockFeignService.reduce();
return "下单成功 openfeign "+reduce;
}
}
4.启动的时候在服务调用端的启动类加上注解@EnableFeignClients
package com.lipengg;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author lipengg
* @date 2023/5/10
*/
@SpringBootApplication
@EnableFeignClients
public class OrderOpenFeignApplication {
public static void main(String[] args) throws InterruptedException {
SpringApplication.run(OrderOpenFeignApplication.class, args);
}
}
3.openfeign自定义配置和规则
3.1日志配置
日志的级别
- NONE [性能最佳,适用于生成环境]:不记录任何日志; 也是默认值
- BASIC[适用于生产环境追踪问题]:仅记录请求方法,url,响应状态码以及执行时间;
- HEADERS:记录BASIC级别的日志,记录请求和响应的header;
- FULL[比较适用与开发环境和定位问题]:记录请求和响应的header,body和元数据
注意:在看日志的时候,由于springboot的默认日志是info 而feign的日志级别是debug,info的级别是大于debug的
所以启动的时候直接启动,即使配置了,也是看不到日志的,要么以debug运行,要么在配置类配置springboot 的日志级别
# com.lipengg.feign 只修改feign包下的日志级别 如果在level下直接配置则是全局生效的
logging:
# level: debug
level:
com:
lipengg:
feign: debug
- 定义一个配置类,也是全局生效的方式
package com.lipengg.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author lipengg
* @date 2023/5/21
*/
// @Configuration 全局配置,对所有的服务提供方都生效
@Configuration
public class OpenFeignConfig {
@Bean
public Logger.Level feignLoggerLever() {
return Logger.Level.FULL;
}
}
FULL日志内容
-
局部配置
第一种 1)配置类取消@Configuration ; 2)在feign包下面声明调用服务时利用configuration属性指定配置类
package com.lipengg.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author lipengg
* @date 2023/5/21
*/
// @Configuration 全局配置,对所有的服务提供方都生效
@Configuration
public class OpenFeignConfig {
@Bean
public Logger.Level feignLoggerLever() {
return Logger.Level.FULL;
}
}
package com.lipengg.feign;
import com.lipengg.config.OpenFeignConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @author lipengg
* @date 2023/5/21
*/
// 指定需要调用的服务的名称,name是服务名称,stock是controller最开始的@RequestMapping的地址,
// 针对当前指定configuration指定日志级别
@FeignClient(name = "stock-service",path = "stock",configuration = OpenFeignConfig.class)
public interface StockFeignService {
@GetMapping("/reduce") // 这里的路径和参数要和controller接口中的保持一致
String reduce();
}
第二种:利用配置文件
# feign日志的局部配置
feign:
client:
config:
stock-service: # 需要配置日志级别的服务名
loggerLevel: BASIC
BASIC的日志内容
3.2契约配置
首先,何为契约配置,我们知道openfeign是支持spring mvc注解的,但是feign本身是不支持的,契约配置的作用就是为了让openfeign支撑feign的原生注解;
一般情况下并不需要,但是一种情况,如果原本代码使用的是feign,而后续需要升级到openfeign,此时因为原始工程使用的是feign的原生注解,在openfeign中默认是不支持的,所以此时为了不修改代码本身,需要让openfeign支持feign的原生注解,此时就用到了契约配置
-
配置类配置
@Configuration public class OpenFeignConfig { /** * 修改契约配置,支撑feign的原生注解 * @return */ @Bean public Contract feignContract(){ return new Contract.Default(); } }
-
配置文件配置
# feign日志的局部配置 feign: client: config: stock-service: # 需要配置日志级别的服务名 loggerLevel: FULL contract: feign.Contract.Default # 契约配置,支撑feign原生注解
在修改了契约配置之后,在使用spring mvc的注解,即openfeign的注解就会报错
3.3超时时间配置
通过Options可以配置连接超时时间和读取超时时间,最新的Options的第一个参数是连接的超时时间(ms),默认值是10s;第二个参数是请求处理超时时间(ms),默认时间是60s
-
全局配置
// @Configuration 全局配置,对所有的服务提供方都生效 @Configuration public class OpenFeignConfig { @Bean public Request.Options options(){ return new Request.Options(500,500); } }
-
配置文件
# feign日志的局部配置 feign: client: config: stock-service: # 需要配置日志级别的服务名 loggerLevel: FULL # contract: feign.Contract.Default # 契约配置,支撑feign原生注解 connectTimeout: 5000 # 单位ms readTimeout: 3000 # 单位ms
3.4自定义拦截器
feign的拦截器和我们之前的spingboot中的拦截器不同,springboot是继承了spring mvc,它的拦截器是前端在请求后台服务的时候,在客户端与服务间之间加的一个"关卡";例如登录身份认证,就像是安全框架spring security和shiro一样
而feign的拦截器是后台服务与服务之间的使用的一个"关卡",例如日志记录
public class FeignAuthRequestInterceptor implements RequestInterceptor {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void apply(RequestTemplate requestTemplate) {
// 业务逻辑
String access_token = UUID.randomUUID().toString();
requestTemplate.header("Authorization",access_token);
// 做日志记录
logger.info("xxxx");
}
}
- 通过config配置
@Configuration
public class OpenFeignConfig {
@Bean
public Logger.Level feignLoggerLever() {
return Logger.Level.FULL;
}
// 自定有拦截器
@Bean
public FeignAuthRequestInterceptor feignAuthRequestInterceptor(){
return new FeignAuthRequestInterceptor();
}
}
- 通过配置文件配置
# feign日志的局部配置
feign:
client:
config:
stock-service: # 需要配置日志级别的服务名
loggerLevel: FULL
contract: feign.Contract.Default # 契约配置,支撑feign原生注解
connectTimeout: 5000 # 单位ms
readTimeout: 3000 # 单位ms
requestInterceptors[0]: com.lipengg.config.FeignAuthRequestInterceptor # 配置自定义拦截器