OpenFeign是一个显示声明式的WebService客户端。使用OpenFeign能让编写Web Service客户端更加简单。使用时只需定义服务接口,然后在上面添加注解。OpenFeign也支持可拔插式的编码和解码器。Spring cloud对feign进行了封装,使其支持MVC注解和HttpMessageConverts。和Eureka(服务注册中心)和Ribbon组合可以实现负载均衡。在Spring Cloud中使用OpenFeign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求,非常的方便
一、pom依赖
之前在父项目已经引入了Spring-cloud,现在在父项目再引入OpenFegin的依赖,子项目就可以都使用了
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
二、yml配置文件
server:
port: 8086
spring:
application:
name: openfeign-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
management:
endpoints:
web:
exposure:
include: '*'
三、启动类添加注解
在主启动类上加入@EnableFeignClients
注解,标记为启用OpenFeign,具体如下:
@SpringBootApplication
@EnableDiscoveryClient
// openFeign注解,添加该注解后,该服务就可以使用openFeign
@EnableFeignClients
public class OpenfeignConsumer8086Application {
public static void main(String[] args) {
SpringApplication.run(OpenfeignConsumer8086Application.class, args);
}
}
笔者这里再提一句,假如是分布式项目,将OpenFeign抽取为一个单独的服务模块时,可能出现我OpenFeign中的包名和其他模块不一致,可以自己声明FeignClient组件的
basePackages
设置一下FeignClient的扫描路径。示例如下:
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.alibaba.provider.feigns")
public class Consumer {
public static void main(String[] args) {
SpringApplication.run(Consumer.class, args);
}
}
四、Service层
package com.cloud.openfeignconsumer8086.service;
import com.cloud.cloudalibabacommons.entity.JsonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* 此接口就是配合使用OpenFeign的接口,
* 在此接口中添加@FeignClient接口,
* 同时标注要调用的服务端名称,
* 使用与服务提供者方法签名一致的抽象方法来表示远程调用的具体内容
*/
@Service
// 远程调用的服务名称
@FeignClient("nacos-provider")
public interface OpenFeignService {
/**
* 此方法表示远程调用demo/info/{id}接口
*/
@GetMapping("data/info/{id}")
public JsonResult<String> info(@PathVariable("id") Long id);
}
五、Controller
@RestController
@RequestMapping("demo")
public class DemoController {
@Autowired
private OpenFeignService openFeignService;
@GetMapping("getInfo/{id}")
public JsonResult<String> getInfo(@PathVariable("id") Long id){
return openFeignService.info(id);
}
}
控制超时时间
OpenFeign 客户端默认等待1秒钟,但是如果服务端业务超过1秒,则会报错。可以通过自定义配置来设置OpenFeign的请求过时时间。
由于OpenFeign 底层是Ribbon 。所以超时控制由Ribbon来控制。在yml文件中配置:
#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
#指的是建立连接后从服务器读取到可用资源所用的时间
ReadTimeout: 5000
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ConnectTimeout: 5000
日志打印
Feign 提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解 Feign 中 Http 请求的细节
日志级别
- NONE:默认的,不显示任何日志;
- BASIC:仅记录请求方法、URL、响应状态码及执行时间;
- HEADERS:除了 BASIC 中定义的信息之外,还有请求和响应的头信息;
- FULL:除了 HEADERS 中定义的信息之外,还有请求和响应的正文及元数据。
具体使用
启动类
@SpringBootApplication
@EnableDiscoveryClient
// openFeign注解,添加该注解后,该服务就可以使用openFeign
@EnableFeignClients
public class OpenfeignConsumer8086Application {
public static void main(String[] args) {
SpringApplication.run(OpenfeignConsumer8086Application.class, args);
}
@Bean
Logger.Level feignLoggerLevel(){
//开启详细日志
return Logger.Level.FULL;
}
}
配置文件
logging:
level:
# openfeign日志以什么级别监控哪个接口
com.cloud.openfeignconsumer8086.service.OpenFeignService: debug
访问时可以看到日志记录:
六、Sentinel整合OpenFeign
<!-- sentinel依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- openFeign依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
2、yml配置
# 激活Sentinel对openFeign的支持
feign:
sentinel:
enabled: true
# 方便查看日志
logging:
level:
com.cloud.cloudalibabacustomer8084.service.FeignService: debug
3、 Service接口
// 注入到Spring容器
@Service
/**
* value属性定义访问服务的名称
* fallback属性定义异常的处理,在调用第三方服务时,一旦抛出了异常(例如网络异常、超时异常等),
* 由fallback定义的对应接口实现方法来处理具体逻辑
*/
@FeignClient(value="nacos-provider",fallback = FeignServiceImpl.class)
public interface FeignService {
@GetMapping("/data/info/{id}")
public JsonResult<String> info(@PathVariable("id") Long id);
}
4、Service实现类——处理Feign调用的异常
// 注入到Spring容器
@Component
/**
* fallback对应写了该类,该类也需要去实现使用Feign的接口,
* 保持一致的对应关系
*/
public class FeignServiceImpl implements FeignService {
/**
* 此处重写的方法可以理解为服务降级
* 当服务消费者无法远程调用时,进入该方法处理,
* 此时可以通过fallback给出另一套解决方案,
* 例如:调用2.0接口出问题了,那么此时可以去调用1.0接口
* @param id
* @return
*/
@Override
public JsonResult<String> info(Long id) {
return new JsonResult<String>(446,"网络调用异常,请联系系统管理员");
}
}
5、控制器类
@Autowired
private FeignService feignService;
@GetMapping("getInfo/{id}")
public JsonResult<String> getInfo(@PathVariable("id") Long id){
return feignService.info(id);
}