来源
Feign使得 Java HTTP
客户端编写更方便。Feign
灵感来源于Retrofit
、JAXRS-2.0
和WebSocket
。Feign
最初是为了降低统一绑定Denominator
到 HTTP API
的复杂度,不区分是否支持 Restful
。
Retrofit是Square
开发的一个Android
和Java
的REST
客户端库。
github地址:https://github.com/square/retrofit
JAX-RS(Java API for RESTful Web Services
) 2.0 又称JSR 339
不仅定义了一套用于构建 RESTful
网络服务的 API
,同时也通过增强客户端 API
功能简化了REST
客户端的构建过程。
github地址:https://github.com/eclipse-ee4j/jaxrs-api
WebSocket 是一种网络通信协议。RFC6455
定义了它的通信标准。
协议说明:https://tools.ietf.org/html/rfc6455
Denominator是一个用于操作DNS
云的可移植Java
库
github地址:https://github.com/Netflix/Denominator
简介
Spring Cloud Netflix
的微服务都是以 HTTP
接口的形式暴露的,
所以调用方式有:
JDK原生的URLConnection
Apache的Http Client
Netty的异步HTTP Client
Spring的RestTemplate
Feign
而 Feign 是一个使用起来更加方便的 HTTP
客戶端,使用起来就像是调用自身工程的方法,而感觉不到是调用远程方法。feign
还支持可插拔的编码器和解码器,Spring
在用的时候增加了对@requestMapping
的处理,Feign
的目的是尽量的减少资源和代码来实现和HTTP API
的连接。通过自定义的编码解码器以及错误处理,可以编写任何基于文本的HTTP API
。
github地址:https://github.com/OpenFeign/feign
在源码中可以看到子模块包括Ribbon
和Hystrix
,所以feign
是基于Ribbon
和Hystrix
的声明式服务调用组件。Feign是一种声明式、模板化的HTTP客户端。
`
实现声明式REST客户端Feign
引入Spring Cloud Feign
依赖以及相关依赖
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
注:网上有的文章说引入的依赖是spring-cloud-starter-feign
,其实官方不再推荐使用,推荐使用spring-cloud-starter-openfeign
在应用主类中通过@EnableFeignClients
注解开启Feign
功能,因为要注册服务,所以还要使用@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients
@EnableEurekaClient
public class SpringcloudFeignApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudFeignApplication.class, args);
}
}
修改yml
配置文件
server:
port: 8088
eureka:
client:
service-url:
defaultZone: http://localhost:9090/eureka
spring:
application:
name: springcloud-feign-client
重点:Feign声明式/模块化体现
接下来定义服务接口类
使用@FeignClient("springcloud-eureka-client")
注解来绑定该接口对应springcloud-eureka-client
服务
@Component
@FeignClient(name = "springcloud-eureka-client")
public interface Client {
@GetMapping("/client")
public String getInfo();
}
通过声明式的注解,提供一个供其它服务调用的 Client。
@FeignClient
用于通知Feign
组件对该接口进行代理(不需要编写接口实现),使用者可直接通过@Autowired
注入
注:多个feignCLient
类中@FeignClient
注解中的name
值不能重复,url
可以重复
Spring Cloud
应用在启动时,Feign
会扫描标有@FeignClient
注解的接口,生成代理,并注册到Spring
容器中。生成代理时Feign
会为每个接口方法创建一个RequetTemplate
对象,该对象封装了HTTP
请求需要的全部信息,请求参数名、请求方法等信息都是在这个过程中确定的,Feign
的模板化就体现在这里。
注意:绑定的接口服务必须是对应服务上存在的接口
例如我把接口名改为client123
便会报如下错误
也就是找不到对应的接口服务,所绑定的
springcloud-eureka-client
没有client123
接口
这是springcloud-eureka-client
服务中的client
接口
@RestController
public class DiscoveryController {
@Autowired
private DiscoveryClient discoveryClient;
@Value("${server.port}")
private String ip;
@GetMapping("/client")
public String client() {
String services = "调用的服务是: " + discoveryClient.getServices()+" 对应的端口号 :"+ip;
System.out.println("调用的服务是: " + discoveryClient.getServices()+" 对应的端口号 :"+ip);
return services;
}
}
调用上面定义的接口
@RestController
public class FeignClientController {
@Autowired
Client client;
@GetMapping("/info")
public String getInfo(){
return client.getInfo();
};
}
这里的接口名就任意取了,这里主要是获取绑定服务的接口的信息。
整体项目结构
Eureka服务端 端口号是9090
Eureka客户端 端口号是8082 服务名springcloud-eureka-client
feign消费者客户端 端口号是8088
(如需测试负载均衡的可以再启动一个端口号为8081的服务,服务名同样是springcloud-eureka-client
)
启动服务进行测试
先启动服务端再启动客户端,客户端启动顺序没要求
访问http://localhost:9090服务注册中心
在服务注册中心可以看到,服务提供者和消费者都注册好了
访问feign定义的接口/info
,http://localhost:8088/info
测试负载均衡
服务列表
访问http://localhost:8088/info
刷新下,再次访问
实现了与
Ribbon
相同的负载均衡功能
实现Feign熔断
需要先写一个调用延迟或失败时调用的类
@Component
public class FailClass implements Client{
@Override
public String getInfo() {
return "服务中断连接,请联系管理员";
}
}
需要实现自定义服务接口的方法,以至于显示对应服务的对应接口调用失败的返回信息
然后在自定义服务接口中添加fallback
异常处理回调。
@Component
@FeignClient(name = "springcloud-eureka-client",fallback = FailClass.class)
public interface Client {
@GetMapping("/client")
public String getInfo();
}
还需要在yml
配置文件中开启熔断,默认为false
feign:
hystrix:
enabled: true
关闭两个springcloud-eureka-client
服务后访问http://localhost:8088/info会显示
总结:
其实通过Feign
封装了HTTP
调用服务方法,使得客户端像调用本地方法那样直接调用方法,Feign
本质上是个HTTP
客户端
Feign继承特性用起来确实很方便,但是也带来一个问题,就是服务提供者和服务消费者的耦合度太高,此时如果服务提供者修改了一个接口的定义,服务消费者可能也得跟着变化,进而带来很多未知的工作量,如果通过此方法来实现接口共享的话,建议严格遵守面向对象的开闭原则,尽可能低做好前后版本兼容,防止因为版本原因造成接口定义的不一致。
推荐文章
Feign相关参数配置:https://blog.csdn.net/u012702547/article/details/78327668?locationNum=10&fps=1
Feign源码分析:https://blog.csdn.net/forezp/article/details/73480304