在项目开发过程中,我们开发的项目或多或少都会与其他交互的系统进行对接集成,或者是微服务项目之间进行调用,双方相互调用接口来获取或者传递数据,以往我们使用的方式可能有 httpClient、okhttp、httpUrlConnection 等等,今天来学习一下如何使用 openfeign 来进行调用。
Feign 是 Springcloud 组件中的一个轻量级 Restful 的 HTTP 服务客户端,Feign 内置了 Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign 的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。
OpenFeign 是 springcloud 在Feign的基础上支持了 SpringMVC 的注解,如 @RequestMapping 等等。OpenFeign 的 @FeignClient 可以解析 SpringMVC 的 @RequestMapping 注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
1、Feign 本身不支持 Spring MVC 的注解,它有一套自己的注解
2、Fegin 是 Netflix 公司产品,停止更新了。
3、使用 OpenFeign 可以简化项目之间接口的调用,我们不需要关心 http 调用的代码
创建一个基本的 springboot 项目
<dependencies>
<dependency>
<groupId> org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
server:
port: 8081
@RestController
@RequestMapping("/demo")
public class FeignDemoController {
@GetMapping("/test")
public String test(){
return "hello openfegin";
}
}
创建一个基本的 springboot 项目
这里要注意springboot 和 springCloud 版本
当前 springboot 版本 2.3.4.RELEASE
springcloud 版本 Hoxton.SR4
<properties>
<java.version>1.8</java.version>
<spring.cloud-version>Hoxton.SR4</spring.cloud-version>
</properties>
<dependencies>
<dependency>
<groupId> org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
开启 feign 功能
@SpringBootApplication
@EnableFeignClients
public class OpenfeginApplication {
public static void main(String[] args) {
SpringApplication.run(OpenfeginApplication.class, args);
}
}
@FeignClient 标注该类是一个feign接口
name:因为这里并未进行服务注册,所以就随便命名一个
url:被调用的服务提供方的接口地址
@FeignClient(name = "demo",url = "http://localhost:8081/demo")
public interface FeginDemo {
@GetMapping("test") //被调用接口的请求类型
String test();
}
@RestController
@RequestMapping("/feginDemo")
public class FeginDemoController {
@Autowired
FeginDemo feginDemo;
@GetMapping("/test")
public String test(){
String test = feginDemo.test();
return test;
}
}
启动项目,访问 http://localhost:8080/feginDemo/test
接口调用成功!
那么这里呢,我们就实现了通过 openfeign 完成一次简单的接口调用,如果没有使用 openfeign 这里的调用我们就只能通过 httpclient、okhttp 等方式来调用了,使用了 openfeign 之后,你会发现,调用别人的接口竟是如此简单。
在调用接口过程中,由于是调用别人接口,肯定会存在一些意外因素,比如被调用的服务提供方系统宕机了,访问不到了等情况,如下
比如我停止 被调用的服务提供方,再去进行调用
那么这个时候我们就需要用到服务熔断了,在对方服务异常的时候,返回这个信息肯定不太友好,我们来让它稍微友好一些
openfeign 中默认集成了 Hystrix
feign:
hystrix:
enabled: true
创建一个类,实现我们的 FeginDemo ,然后实现接口中的方法,进行重写
@Component
public class ErrorMessage implements FeginDemo {
@Override
public String test() {
return "服务器开小差了哦,请稍后再试";
}
}
fallback:配置刚才的实现类 ErrorMessage
@FeignClient(name = "demo",url = "http://localhost:8081/demo",fallback = ErrorMessage.class)
public interface FeginDemo {
@GetMapping("test")
String test();
}
重新启动一下服务
再进行访问
对于用户来说,这样是不是更加友好一点了呢?总比你一连串的英文往人家脸上呼来的好吧
logging:
level:
com.wxw.openfeign: debug
@Configuration
public class FeignLogConfiguration {
// NONE:不记录任何日志信息,这是默认值。
// BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
// HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
// FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
@FeignClient(name = "demo",url = "http://localhost:8081/demo",
fallback = ErrorMessage.class,configuration = FeignLogConfiguration.class)
public interface FeginDemo {
@GetMapping("test")
String test();
}