Feign:对Ribbon进行了封装,整合了Ribbon和SpringMVC注解,底层依然使用http进行微服务之间的调用。它提供了http请求的模板,通过编写接口和插入注解,就可以定义好参数、格式、地址等信息,由Feign完全代理http请求,使微服务之间的调用更加方便。
1、依赖:
<!--eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--web包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--导入Feign的包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、入口类上添加注解:
/*
* @EnableFeignClients :开启Feign支持
* value :feign接口的包:数组(可多个接口包)(value可省略)
* /
@EnableFeignClients(value = {"feign接口的包"})
3、Feign接口:
/**
* @FeignClient 客户端
* value = "注册到EurekaServer注册中心的微服务名"
*
* 注意:接口中的方法必须与目标服务controller中的方法完全一致(路径必须为完整路径)
*/
@FeignClient(value = "movie-server")
public interface BuyFeignClient {
/**
* 保存电影票
* @param movieTicket
* @return
*/
@PostMapping("/save")
AjaxResult saveMovieTicket(@RequestBody MovieTicket movieTicket);
/**
* 根据id查
* @param id
* @return
*/
@GetMapping("/movie/{id}")
AjaxResult getById(@PathVariable("id") Long id);
/**
* 根据id修改
* @param movieTicket
*/
@PostMapping("/movie/update")
void updateMovieTicket(@RequestBody MovieTicket movieTicket);
}
4、参数配置 application.yml
4.1、基本配置与注册到EurekaServer注册中心
server:
port: 1040 #启动端口
eureka:
client:
serviceUrl:
defaultZone: http://user:admin@peer1:1011/eureka/,http://user:admin@peer2:1012/eureka/,http://user:admin@peer3:1013/eureka/
# 注册到所有Eureka服务
# peer1 映射了ip地址
# user 访问Eureka服务的用户名
# admin 访问Eureka服务的密码
instance:
prefer-ip-address: true # 使用ip注册到Euraka
instance-id: buy-server:1040 # 实例id
spring:
application:
name: buy-server # 服务名
4.2、负载均衡
Feign集成了Ribbon,基于Ribbon负载均衡配置
#配置访问movie-server服务的负载均衡算法为:随机
#若要全局配置,则不加movie-server,直接用 ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
movie-server:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #使用的具体的算法
#feign集成了ribbon,所以feign的负载均衡配置可基于ribbon配置
4.3、Feign的超时配置
Feign集成了Ribbon,基于Ribbon配置的超时时间,与重试机制等
ribbon:
MaxAutoRetries: 1 #对当前服务的重试次数
MaxAutoRetriesNextServer: 1 #切换相同Server的次数
OkToRetryOnAllOperations: false # 对所有的操作请求都进行重试,如post就不能重试,如果没做幂等处理,重试多次post会造成数据的多次添加或修改
ConnectTimeout: 1000 #请求连接的超时时间
ReadTimeout: 2000 #请求处理的超时时间
4.4、饥饿加载
ribbon:
eager-load:
enabled: true #开启饥饿加载(程序启动,则会加载Ribbon)
clients: movie-server #针对于哪些服务需要饥饿加载。需要添加服务则:movie-server,xxx-server,xxx-server
4.5、Hystrix熔断器配置
Feign默认集成了Hystrix熔断器,但高版本的Feign关闭了Hystrix熔断器。
feign:
hystrix:
enabled: true #开启熔断支持
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000 #hystrix超时时间
#如果配置ribbon的重试,hystrix的超时时间要大于ribbon的超时时间,
#计算方式:timeoutInMilliseconds时间 = ReadTimeout时间 * (1 + MaxAutoRetries次数 + MaxAutoRetriesNextServer次数)
5、Feign日志调试开启
5.1、配置类
@Configuration //声明为配置类
public class FeignConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL; //打印Feign的所有日志
}
}
5.2、application.yml配置
#开启日志打印
logging:
level:
cn.source: debug
#日志打印级别为debug
6、Hystrix熔断
6.1、Fiegn接口熔断-fallbackFactory配置
在Feign接口的@FeignClient注解中添加fallbackFactory属性。
/**
* @FeignClient feign客户端
* value = "注册到EurekaServer注册中心的微服务名"
* BuyFeignClientFallbackFactory 托底类
*
* 注意:接口中的方法必须与目标服务controller中的方法完全一致(路径必须为完整路径)
*/
@FeignClient(value = "movie-server", fallbackFactory = BuyFeignClientFallbackFactory.class)
public interface BuyFeignClient {
/**
* 保存电影票
* @param movieTicket
* @return
*/
@PostMapping("/save")
AjaxResult saveMovieTicket(@RequestBody MovieTicket movieTicket);
}
6.1、托底类:Fiegn接口熔断-fallbackFactory
新建BuyFeignClientFallbackFactory类,实现FallbackFactory接口,需要泛型<Feign接口>。实现create方法
/**
* 托底类
* Fiegn接口熔断-fallbackFactory
* BuyFeignClient
*/
@Component //需要交给Spring管理
public class BuyFeignClientFallbackFactory implements FallbackFactory<BuyFeignClient> {
@HystrixCommand
@Override
public BuyFeignClient create(Throwable cause) {
/**
* 使用匿名内部类,需要new一个接口返回。写入降级数据。
*/
return id -> new AjaxResult (false, "啊呃,网络延迟了!");
}
}
7、注意:微服务项目服务之间feign使用
1、feign接口(和托底类),写在提供接口的微服务下(启动类上添加注解:@EnableFeignClients(basePackages = {"feign接口的包名"}));
2、谁(微服务)需要调用接口,谁(微服务)开feign(启动类上添加注解:@FeignClient(value = "feign接口的包名"));