Feign是一个声明式的Web Service客户端。它的出现使开发Web Service客户端变得很简单。使用Feign只需要创建一个接口加上对应的注解,比如:FeignClient注解。Feign有可插拔的注解,包括Feign注解和JAX-RS注解。
Feign也支持编码器和解码器,Spring Cloud Open Feign对Feign进行增强支持Spring MVC注解,可以像Spring Web一样使用HttpMessageConverters等。
Feign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用Feign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求。
使用Ribbon进行微服务调用,当有同一接口多处调用的情况,那么我们需要在每个调用创建Ribbon,这样无疑造成了重复的工作量,Fegin是在Ribbon的基础上进一步封装,有Fegin来帮助我们定义和实现依赖服务接口的定义,在Fegin的实现下,我们只需创建一个一个接口,通过注解的方式进行配置,即可实现对服务提供方的接口绑定,这样无疑大大简化了工作。
Fegin | OpenFegin |
---|---|
Fegin是Spring Cloud组件中一个轻量级restful风格的HTTP服务客户端;Fegin内置了Ribbon,用来做客户端的负载均衡,去调用服务注册中心的服务。Fegin的使用方式是:使用Fegin的注解定义接口,通过配置就可以调用服务注册中心的服务 | OpenFegin是Spring Cloud在Fegin的基础上支持了SpringMVC注解,可以直接解析例如:@RequestMapping的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用服务 |
spring-cloud-starter-feign | spring-cloud-starter-openfeign |
OpenFeign的详细功能
1.可插拔的注解支持,包括Feign注解和JAX-RS注解。
2.支持可插拔的HTTP编码器和解码器(Gson,Jackson,Sax,JAXB,JAX-RS,SOAP)。
3.支持Hystrix和它的Fallback。
4.支持Ribbon的负载均衡(内置)。
5.支持HTTP请求和响应的压缩。
6.灵活的配置:基于 name 粒度进行配置
7.支持多种客户端:JDK URLConnection、apache httpclient、okhttp,ribbon)
8.支持日志
9.支持错误重试
10.url支持占位符
11.可以不依赖注册中心独立运行
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020artifactId>
<groupId>com.zjf.studygroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>cloud-consumer-feign-order80artifactId>
<dependencies>
<dependency>
<groupId>com.zjf.studygroupId>
<artifactId>com-api-commonsartifactId>
<version>${project.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
project>
server:
port: 80
spring:
application:
name: cloud-consumer-feign-order80
eureka:
client:
# false 表示不向注册中心注册自己(客户端需要向服务端注册自己)
register-with-eureka: true
# false 表示自己就是注册中心, 我的职责是去维护服务实例,并不需要去检索服务
fetch-registry: true
service-url:
#defaultZone: http://localhost:7001/eureka/ 连接单机版eureka
# 设置与 Eureka Server 交互的地址查询服务和注册服务都需要依赖的这个地址,这里连接的是eureka集群
defaultZone: http://localhost:7001/eureka/,http://eureka7002.com:7002/eureka/
instance:
#配置Eureka显示主机名
instance-id: feign-order80
#显示主机IP地址
prefer-ip-address: true
-主启动类,加上@EnableFeignClients注解
/**
* @author 张江丰
* @version 9:58
*
*/
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableFeignClients
public class FeginOrderMain80 {
public static void main(String[] args) {
SpringApplication.run(FeginOrderMain80.class,args);
}
}
@EnableEurekaClient:声明当前服务是Eureka客户端
@EnableDiscoveryClient:用于微服务发现
@EnableFeignClients:声明当前服务是Fegin客户端
-OpenFegin接口,支持MVC注解
/**
* @author 张江丰
* @version ${Date} 10:07
* @FeignClient 类似于webServce使用方法,value指定微服务提供者名称,如果不是微服务通过url配置访问ip地址
* Fegin是针对于Ribbon的进一步封装,Ribbon是基于http协议的,如果服务消费方多个controller需要微服务调用,那么需要配置多个Ribbon。
* 使用Fegin可以简化微服务调用,由我们自己定义微服务提供者,同时在Fegin声明的接口中配置多个服务接口,统一通过Fegin调用微服务提供者。
*/
@Component
@FeignClient(value = "http://CLOUD-PAYMENT-SERVICE")
public interface FeginService {
@GetMapping(value = "/payment/lb")
public String getPaymentLB();
@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeout();
}
/**
* @author 张江丰
* @version 10:09
*
*/
@RestController
@Slf4j
public class FeginController {
@Autowired
private FeginService feginService;
@GetMapping("/consumer/payment/lb")
public CommonResult<String> getLb(){
String paymentLB = feginService.getPaymentLB();
return new CommonResult(200,"当前服务端口:"+paymentLB);
}
@GetMapping(value = "/consumer/payment/feign/timeout")
public String paymentFeignTimeout() {
//openfeign-ribbon 客户端默认等待1S
return feginService.paymentFeignTimeout();
}
}
@GetMapping(value = "/payment/lb")
public String getPaymentLB() {
return serverPort;
}
@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeout() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (Exception e){
e.printStackTrace();
} finally {
return serverPort;
}
}
如果使用Fegin进行微服务调用,当服务接口出现延迟;卡顿等情况,OpenFegin会触发超时,默认触发超时1m。
@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeout() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (Exception e){
e.printStackTrace();
} finally {
return serverPort;
}
}
/**
* @author 张江丰
* @version 10:09
*
*/
@RestController
@Slf4j
public class FeginController {
@Autowired
private FeginService feginService;
@GetMapping("/consumer/payment/lb")
public CommonResult<String> getLb(){
String paymentLB = feginService.getPaymentLB();
return new CommonResult(200,"当前服务端口:"+paymentLB);
}
@GetMapping(value = "/consumer/payment/feign/timeout")
public String paymentFeignTimeout() {
//openfeign-ribbon 客户端默认等待1S
return feginService.paymentFeignTimeout();
}
}
#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的实际
ConnectTimeout: 60000
#指的是建立连接后从服务器读取到可用资源所用的时间
ReadTimeout: 60000
Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中Http请求的细节,说白了就是对Feign接口调用情况进行监控和输出。
#设置Fegin的日志级别(全局)
feign:
client:
config:
default:
loggerLevel: FULL
#针对某个Fegin接口的微服务设置输出级别(设置局部的优先级别是最高的)
CLOUD-PAYMENT-SERVICE:
loggerLevel: FULL
logging:
level:
#针对指定的类设置以什么级别监控,输出日志
com.zjf.study.cloud.service.FeginService: debug
方式二:配置Bean+yml配置的方式指定
/**
* @author 张江丰
* @version 11:29
*
*/
@Configuration
public class FeginConfig {
/**
* 设置Fegin日志级别
* @return
*/
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
logging:
level:
#针对指定的类设置以什么级别监控,输出日志
com.zjf.study.cloud.service.FeginService: debug
2020-08-19 17:45:44.230 INFO 1320 --- [ restartedMain] com.zjf.study.cloud.FeginOrderMain80 : No active profile set, falling back to default profiles: default
2020-08-19 17:45:45.071 WARN 1320 --- [ restartedMain] o.s.boot.actuate.endpoint.EndpointId : Endpoint ID 'service-registry' contains invalid characters, please migrate to a valid format.
2020-08-19 17:45:45.184 INFO 1320 --- [ restartedMain] o.s.cloud.context.scope.GenericScope : BeanFactory id=409d6631-451e-35a0-8820-65d122d6974e
2020-08-19 17:45:45.725 INFO 1320 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 80 (http)
2020-08-19 17:45:45.734 INFO 1320 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-08-19 17:45:45.734 INFO 1320 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.29]
2020-08-19 17:45:45.848 INFO 1320 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-08-19 17:45:45.848 INFO 1320 --- [ restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1598 ms
2020-08-19 17:45:45.918 WARN 1320 --- [ restartedMain] c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources.
2020-08-19 17:45:45.919 INFO 1320 --- [ restartedMain] c.n.c.sources.URLConfigurationSource : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2020-08-19 17:45:45.928 INFO 1320 --- [ restartedMain] c.netflix.config.DynamicPropertyFactory : DynamicPropertyFactory is initialized with configuration sources: com.netflix.config.ConcurrentCompositeConfiguration@5a7cee15
2020-08-19 17:45:47.677 WARN 1320 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : Unable to start LiveReload server
2020-08-19 17:45:47.801 WARN 1320 --- [ restartedMain] c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources.
2020-08-19 17:45:47.801 INFO 1320 --- [ restartedMain] c.n.c.sources.URLConfigurationSource : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2020-08-19 17:45:47.920 INFO 1320 --- [ restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-08-19 17:45:50.950 WARN 1320 --- [ restartedMain] ockingLoadBalancerClientRibbonWarnLogger : You already have RibbonLoadBalancerClient on your classpath. It will be used by default. As Spring Cloud Ribbon is in maintenance mode. We recommend switching to BlockingLoadBalancerClient instead. In order to use it, set the value of `spring.cloud.loadbalancer.ribbon.enabled` to `false` or remove spring-cloud-starter-netflix-ribbon from your project.
2020-08-19 17:45:50.985 INFO 1320 --- [ restartedMain] o.s.b.a.e.web.EndpointLinksResolver : Exposing 2 endpoint(s) beneath base path '/actuator'
2020-08-19 17:45:51.012 INFO 1320 --- [ restartedMain] o.s.c.n.eureka.InstanceInfoFactory : Setting initial instance status as: STARTING
2020-08-19 17:45:51.044 INFO 1320 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Initializing Eureka in region us-east-1
2020-08-19 17:45:51.144 INFO 1320 --- [ restartedMain] c.n.d.provider.DiscoveryJerseyProvider : Using JSON encoding codec LegacyJacksonJson
2020-08-19 17:45:51.144 INFO 1320 --- [ restartedMain] c.n.d.provider.DiscoveryJerseyProvider : Using JSON decoding codec LegacyJacksonJson
2020-08-19 17:45:51.255 INFO 1320 --- [ restartedMain] c.n.d.provider.DiscoveryJerseyProvider : Using XML encoding codec XStreamXml
2020-08-19 17:45:51.255 INFO 1320 --- [ restartedMain] c.n.d.provider.DiscoveryJerseyProvider : Using XML decoding codec XStreamXml
2020-08-19 17:45:51.411 INFO 1320 --- [ restartedMain] c.n.d.s.r.aws.ConfigClusterResolver : Resolving eureka endpoints via configuration
2020-08-19 17:45:52.363 INFO 1320 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Disable delta property : false
2020-08-19 17:45:52.363 INFO 1320 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Single vip registry refresh property : null
2020-08-19 17:45:52.363 INFO 1320 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Force full registry fetch : false
2020-08-19 17:45:52.363 INFO 1320 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Application is null : false
2020-08-19 17:45:52.363 INFO 1320 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Registered Applications size is zero : true
2020-08-19 17:45:52.363 INFO 1320 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Application version is -1: true
2020-08-19 17:45:52.363 INFO 1320 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Getting all instance registry info from the eureka server
2020-08-19 17:45:52.505 INFO 1320 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : The response status is 200
2020-08-19 17:45:52.507 INFO 1320 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Starting heartbeat executor: renew interval is: 30
2020-08-19 17:45:52.510 INFO 1320 --- [ restartedMain] c.n.discovery.InstanceInfoReplicator : InstanceInfoReplicator onDemand update allowed rate per min is 4
2020-08-19 17:45:52.513 INFO 1320 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Discovery Client initialized at timestamp 1597830352512 with initial instances count: 2
2020-08-19 17:45:52.515 INFO 1320 --- [ restartedMain] o.s.c.n.e.s.EurekaServiceRegistry : Registering application CLOUD-CONSUMER-FEIGN-ORDER80 with eureka with status UP
2020-08-19 17:45:52.515 INFO 1320 --- [ restartedMain] com.netflix.discovery.DiscoveryClient : Saw local status change event StatusChangeEvent [timestamp=1597830352515, current=UP, previous=STARTING]
2020-08-19 17:45:52.517 INFO 1320 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_CLOUD-CONSUMER-FEIGN-ORDER80/feign-order80: registering service...
2020-08-19 17:45:52.557 INFO 1320 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_CLOUD-CONSUMER-FEIGN-ORDER80/feign-order80 - registration status: 204
2020-08-19 17:45:52.563 INFO 1320 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 80 (http) with context path ''
2020-08-19 17:45:52.564 INFO 1320 --- [ restartedMain] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 80
2020-08-19 17:45:53.986 INFO 1320 --- [ restartedMain] com.zjf.study.cloud.FeginOrderMain80 : Started FeginOrderMain80 in 13.791 seconds (JVM running for 15.739)
2020-08-19 17:46:16.917 INFO 1320 --- [p-nio-80-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-08-19 17:46:16.917 INFO 1320 --- [p-nio-80-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-08-19 17:46:16.924 INFO 1320 --- [p-nio-80-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 6 ms
2020-08-19 17:46:16.952 DEBUG 1320 --- [p-nio-80-exec-1] c.zjf.study.cloud.service.FeginService : [FeginService#getPaymentLB] ---> GET http://CLOUD-PAYMENT-SERVICE/payment/lb HTTP/1.1
2020-08-19 17:46:16.952 DEBUG 1320 --- [p-nio-80-exec-1] c.zjf.study.cloud.service.FeginService : [FeginService#getPaymentLB] ---> END HTTP (0-byte body)
2020-08-19 17:46:17.089 INFO 1320 --- [p-nio-80-exec-1] c.netflix.config.ChainedDynamicProperty : Flipping property: CLOUD-PAYMENT-SERVICE.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-08-19 17:46:17.118 INFO 1320 --- [p-nio-80-exec-1] c.n.u.concurrent.ShutdownEnabledTimer : Shutdown hook installed for: NFLoadBalancer-PingTimer-CLOUD-PAYMENT-SERVICE
2020-08-19 17:46:17.119 INFO 1320 --- [p-nio-80-exec-1] c.netflix.loadbalancer.BaseLoadBalancer : Client: CLOUD-PAYMENT-SERVICE instantiated a LoadBalancer: DynamicServerListLoadBalancer:{
NFLoadBalancer:name=CLOUD-PAYMENT-SERVICE,current list of Servers=[],Load balancer stats=Zone stats: {
},Server stats: []}ServerList:null
2020-08-19 17:46:17.127 INFO 1320 --- [p-nio-80-exec-1] c.n.l.DynamicServerListLoadBalancer : Using serverListUpdater PollingServerListUpdater
2020-08-19 17:46:17.147 INFO 1320 --- [p-nio-80-exec-1] c.netflix.config.ChainedDynamicProperty : Flipping property: CLOUD-PAYMENT-SERVICE.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-08-19 17:46:17.149 INFO 1320 --- [p-nio-80-exec-1] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client CLOUD-PAYMENT-SERVICE initialized: DynamicServerListLoadBalancer:{
NFLoadBalancer:name=CLOUD-PAYMENT-SERVICE,current list of Servers=[172.23.200.33:8002],Load balancer stats=Zone stats: {
defaultzone=[Zone:defaultzone; Instance count:1; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]
},Server stats: [[Server:172.23.200.33:8002; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@d8bee38
2020-08-19 17:46:17.221 DEBUG 1320 --- [p-nio-80-exec-1] c.zjf.study.cloud.service.FeginService : [FeginService#getPaymentLB] <--- HTTP/1.1 200 (268ms)
2020-08-19 17:46:17.222 DEBUG 1320 --- [p-nio-80-exec-1] c.zjf.study.cloud.service.FeginService : [FeginService#getPaymentLB] connection: keep-alive
2020-08-19 17:46:17.222 DEBUG 1320 --- [p-nio-80-exec-1] c.zjf.study.cloud.service.FeginService : [FeginService#getPaymentLB] content-length: 4
2020-08-19 17:46:17.222 DEBUG 1320 --- [p-nio-80-exec-1] c.zjf.study.cloud.service.FeginService : [FeginService#getPaymentLB] content-type: text/plain;charset=UTF-8
2020-08-19 17:46:17.222 DEBUG 1320 --- [p-nio-80-exec-1] c.zjf.study.cloud.service.FeginService : [FeginService#getPaymentLB] date: Wed, 19 Aug 2020 09:46:17 GMT
2020-08-19 17:46:17.222 DEBUG 1320 --- [p-nio-80-exec-1] c.zjf.study.cloud.service.FeginService : [FeginService#getPaymentLB] keep-alive: timeout=60
2020-08-19 17:46:17.222 DEBUG 1320 --- [p-nio-80-exec-1] c.zjf.study.cloud.service.FeginService : [FeginService#getPaymentLB]
2020-08-19 17:46:17.223 DEBUG 1320 --- [p-nio-80-exec-1] c.zjf.study.cloud.service.FeginService : [FeginService#getPaymentLB] 8002
2020-08-19 17:46:17.224 DEBUG 1320 --- [p-nio-80-exec-1] c.zjf.study.cloud.service.FeginService : [FeginService#getPaymentLB] <--- END HTTP (4-byte body)
2020-08-19 17:46:18.131 INFO 1320 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty : Flipping property: CLOUD-PAYMENT-SERVICE.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647