OpenFeign是一种声明式、模板化的HTTP客户端。使用OpenFeign能让编写Web Service客户端更加简单。使用时只需定义服务接口,然后在上面添加注解。OpenFeign也支持可拔插式的编码和解码器。Spring cloud对Feign进行了封装,使其支持MVC注解和HttpMessageConverts。和Eureka和Ribbon组合可以实现负载均衡。
OpenFeign默认将Ribbon作为负载均衡器,直接内置了 Ribbon。在导入OpenFeign 依赖后无需专门导入Ribbon 依赖。
在Spring Cloud中使用OpenFeign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求,非常的方便。
Fegin与OpenFeign1、导入依赖
org.springframework.cloud
spring-cloud-starter-openfeign
2、在服务消费者主程序类上添加注解 @EnableFeignClients,启用 Feign 客户端
//开启当前服务支持Feign客户端,作用扫描所有客户端接口
@EnableFeignClients
//或者
@EnableFeignClients(basePackages = "com.example.demo.consumer.feign")
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class,args);
}
}
我们在启动类上面添加了 @EnableFeignClients 注解,就是表明当前【服务消费者】中有的地方想要引用【服务提供方】中的接口。
如果【服务提供方】可以单独启动起来并且注册到注册中心,则我们仅仅在【服务消费者】启动类中添加 @EnableFeignClients 注解即可。
如果【服务提供方】没有单独启动起来,而是以Jar包的形式被引入到【服务消费者】中,则【服务消费者】在启动的时候是不会主动去加载【服务提供方】中标注了@FeignClient注解的interface而去自动生成bean对象,这样我们在【服务消费者】中用@Autowired来实例化【服务提供方】中的标注了@FeignClient注解的接口,是会报错的。
这个时候就需要使用basePackages属性字段去指明【服务消费者】在启动的时候需要扫描【服务提供方】中的标注了@FeignClient注解的接口的包路径。
3、服务提供方定义方法
@RestController
@RequestMapping("/demoserver")
public class DemoServerRest {
@PostMapping("/hello")
public String hello(@RequestBody DemoInputDTO inputDTO) {
String jsonString = JSONObject.toJSONString(inputDTO);
return jsonString;
}
}
4、服务消费者定义服务提供者的 Feign 接口,调用地址要和服务提供者的地址保持一致。
@FeignClient 定义了一个feign
客户端,将远程服务 http://provider-instance-name/demoserver/hello
映射为一个本地Java
方法调用
//标识服务为 feign 的客户端
@FeignClient("provider-instance-name")
public interface ProviderFeignClient {
@PostMapping("/demoserver/hello")
String hello(@RequestBody DemoInputDTO inputDTO);
}
5、服务消费者调用服务提供者的 Feign 接口
@RestController
@RequestMapping("/democlient")
public class ConsumerClientRest {
@Autowired
private ProviderFeignClient service;
@PostMapping("/hello")
public String hello(@RequestBody DemoInputDTO inputDTO) {
return service.hello(inputDTO);
}
}
Openfeign常用配置
1、超时配置
feign:
client:
config:
# 要调用服务的名称
stock-service: #如果是全局配置 则为 default
# feign的配置优先于ribbon
connectTimeout: 2000
readTimeout: 60000
# 重试机制
retryer: feign.Retryer.Default
feign.client.config.default.connectTimeout=2000
feign.client.config.default.readTimeout=60000
feign.client.config.default.retryer=feign.Retryer.Default
2、日志打印
feign:
client:
config:
# 要调用服务的名称
stock-service: #如果是全局配置 则为 default
# 设置日志记录级别,其取值共有none、basic、headers、full
loggerLevel: HEADERS
feign.client.config.default.logger-level=headers
日志级别:
- NONE:默认,不显示任何日志;
- BASIC: 仅记录请求方法、URL、响应状态码及执行时间;
- HEADERS:除了BASIC中定义的信息之外,还有请求头和响应头信息;
- FULL:除了HEADERS中定义的信息之外,还有请求的正文和响应数据。
1、修改配置文件
stock-service:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
2、添加Feign配置类
在 JavaConfig 类中添加负载 Bean 方法。全局所有feign对应服务都可以生效。
@Configuration
public class FeignConfiguration {
/**
* 配置随机的负载均衡策略
* 特点:对所有的服务都生效
*/
@Bean
public IRule loadBalancedRule() {
return new RandomRule();
}
}
4、定义拦截器
/**
* 自定义feign拦截器
*/
public class CustomFeignInterceptor implements RequestInterceptor {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void apply(RequestTemplate requestTemplate) {
//写一些自己的逻辑 带上token 什么之类的
String access_token = UUID.randomUUID().toString();
requestTemplate.header("Authorization",access_token);
logger.info("feign拦截器!");
}
}
注册此拦截器
@Configuration
public class OpenFeignConfig {
/**
* 自定义feign拦截器
* @return
*/
@Bean
public CustomFeignInterceptor customFeignInterceptor() {
return new CustomFeignInterceptor();
}
}
如果写在配置类中,注入的形式则就是全局的拦截器,因为并没有指定是为具体服务进行配置
feign:
client:
config:
stock-service: #服务名
requestInterceptors:
- com.gaby.cloud.order.interceptor.feign.CustomFeignInterceptor