SpringCloud之Feign(声明式服务调用)
前面已经介绍了Ribbon和Hystrix了,可以发现的是:他俩作为基础工具类框架广泛地应用在各个微服务的实现中。我们会发现对这两个框架的使用几乎是同时出现的,并且使用RestTemplate
还是不方便,我们每次都要使用RestTemplate进行远程调用
为了简化我们的开发,Spring Cloud Feign出现了!它基于 Netflix Feign 实现,整合了 Spring Cloud Ribbon 与 Spring Cloud Hystrix, 除了整合这两者的强大功能之外,它还提供了声明式的服务调用(不用RestTemplate)。
1.Feign是一种声明式、模板化的HTTP客户端。
2.在Spring Cloud中使用Feign, 我们可以做到使用HTTP请求远程服务时能与调用本地方法一样的编码体验,
开发者完全感知不到这是远程方法,更感知不到这是个HTTP请求。
一.使用feign实现服务间的调用
cloud-provider-product8080服务
@RestController
@Slf4j
public class ProductFeignClient implements IProductFeignApi {
@Autowired
private IProductService productService;
@Override
public Product get(Long id) {
log.info("ProductFeignClient..get...");
Product product = productService.get(id);
//模拟网络延迟
/* try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
//演示异常后,走降级操作
//int i = 1 / 0;
return product;
}
}
cloud-product-api接口
//接口
//重要注解name--->指定调用哪个服务器 fallback--->降级操作
@FeignClient(name = "PRODUCT-SERVER", fallback =ProductFeignHystrix.class)
public interface IProductFeignApi {
@GetMapping("/products/get/{id}")
Product get(@PathVariable("id") Long id);
}
--------------------------------------------------------------------------------------
//使用feign方式降级
//该类用于product-server服务对外提供接口进行降级保护
//实现IProductFeignApi 接口 目的是为类指定哪些方法需要进行降级处理
@Component
public class ProductFeignHystrix implements IProductFeignApi {
//IProductFeignApi 接口里面的get方法的降级方法
@Override
public Product get(Long id) {
System.out.println("走降级方法了..ProductFeignHystrix..");
return new Product();;
}
}
cloud-consumer-order8090调用product服务
@Service
@Slf4j
public class OrderServiceImpl implements IOrderService {
@Autowired
private IProductFeignApi productFeignApi;
@Override
public Order save(Long userId, Long productId) {
log.info("OrderServiceImpl.save....");
//使用feign方式调用服务
Product product = productFeignApi.get(productId);
return new Order();
}
}
通过上面可以看出Feign优雅地实现了远程调用,并且集成了 Hystrix和Ribbon ,默认轮询方式
依赖pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
yml
server:
port: 8090
spring:
application:
name: order-server
eureka:
client:
#是否将自己注册进去eureka,false为不注册,true注册
registerWithEureka: true
#是否从eureka抓取注册信息,单点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
#eureka客户端向服务端发送心跳的时间间隔,单位为秒,默认是30
lease-renewal-interval-in-seconds: 1
#eureka服务端收到最后一次心跳等待的时间上限,单位为秒,默认是90,超时剔除
lease-expiration-duration-in-seconds: 2
feign:
client:
config:
default:
connectTimeout: 4000
readTimeout: 4000
#开启hystrix,记得一定要开启,默认关闭
hystrix:
enabled: true
启动类
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients //用于告诉框架扫描所有通过注解@FeignClient定义的feign客户端
@EnableCircuitBreaker //@EnableHystrix继承了@EnableCricuitBreaker
public class OrderMain8090 {
public static void main(String[] args) {
SpringApplication.run(OrderMain8090.class, args);
}
}
二.feign的实现原理(底层还是通过ribbon实现远程调用)
三.Feign超时概念
1.源码中默认options中配置的是6000毫秒,但是Feign默认加入了Hystrix,此时默认是1秒超时,
我们可以通过修改配置,修改默认超时时间
2.feign的默认超时时间1秒,如果超时,默认会再发一次请求
3.这个默认重试一次操作,开发中需要慎重设置
假设请求是查询操作,可以配置重试
假设请求是添加操作,不能配置重试操作,如果硬要配置,需要让接口变为幂等函数
1.模拟网络延迟,超时后重试机制
2.当超时后会默认再发起一次请求
3.yml超时设置
#设置5秒
feign:
client:
config:
default:
#请求连接超时时间
connectTimeout: 4000
#请求处理的超时时间
readTimeout: 4000
4.Feign超时重试次数设置
# Max number of retries on the same server (excluding the first try)
#超时重试次数,0表示不重试
sample-client.ribbon.MaxAutoRetries=0
# Max number of next servers to retry (excluding the first server)
#集群中重试几个服务器
sample-client.ribbon.MaxAutoRetriesNextServer=1
5.超时时间调整
现在组件有ribbon feign hystrix 都有超时控制,该如何选择?
推荐方案:
feign或者hystrix > 调用正常业务耗时
hystrix > feign
//hystrix的超时时间应该最大
四.小结
1.Feign是一种声明式、模板化的HTTP客户端
2.Feign集成了ribbon和Hystrix,并且提供了声明式的服务调用,使远程服务调用更加方便
3.Feign中集成的Hystrix默认是关闭的,我们需要在yml配置文件中将其设置为true,则开启
4.feign中有超时重试机制,我们也可以通过修改配置文件来控制重试
5.启动类中需要贴@EnableFeignClients 注解,表示开启feign;
接口上需要贴@FeignClient注解,并指定调用服务名和降级方法;
降级方法需要实现接口
6.具体步骤:
在Spring cloud应用中,当我们要使用feign客户端时,一般要做以下三件事情 :
1.启动类中使用注解@EnableFeignClients启用feign客户端
2.使用注解@FeignClient 定义feign客户端 ,将远程服务http:/xxx映射为一个本地Java方法调用
3.使用注解@Autowired注入使用上面所定义feign的客户端