一、简介:
官方文档: https://cloud.spring.io/spring-cloud-openfeign/
Feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,只需要创建一个接口,接口上面加注解@FeignClient即可,类似controller调用service。Feign与Ribbon和Eureka可以支持负载均衡。
Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这两者的强大功能外,还提供了一种声明式的Web服务客户端定义的方式。
二、为何使用?
使编写Java Http客户端变得容易,它定义和实现依赖服务接口的定义,在在为服务接口上面添加Feign注解即可完成对服务提供方的接口绑定。Feign通过接口的方法调用Rest服务(相当于Ribbon + RestTemplate),该请求发送给Eureka服务器,通过Feign直接找到服务接口,由于在进行服务调用的时候融合了Ribbon技术,所以也支持负载均衡。(Feing面试接口,Ribbon面向RestTemplate)
三、Feign原理
启动时,程序会进行包扫描,扫描所有包下所有@FeignClient注解的类,并将这些类注入到spring的IOC容器中。当定义的Feign中的接口被调用时,通过JDK的动态代理来生成RequestTemplate。
RequestTemplate中包含请求的所有信息,如请求参数,请求URL等。
RequestTemplate声明Request,然后将Request交给client处理,这个client默认是JDK的HTTPUrlConnection,也可以是OKhttp、Apache的HTTPClient等
最后client封装成LoadBaLanceClient,结合ribbon负载均衡地发起调用;
文件查找功能 ctrl+shift+N
LoadBalancerFeignClient类中核心方法excute(Request request,Options options)
四、使用feign步骤
1、在pom.xml文件中加入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、启动类增加@EnableFeignClients
3、 增加一个接口 并用注解 @FeignClient(name="product-service商品服务名称")
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* 商品服务客户端
*/
@FeignClient("product-service")
public interface ProductClient {
@GetMapping("/api/product/find")
String findById(@RequestParam(value = "id") int id);
}
注意: @GetMapping("/api/product/find") 是以get方式提交,/api/product/find必须与商品服务访问的地址相同哦!
(@RequestParam(value = "id") int id)参数必须与商品服务的参数相同.
使用requestBody,应该使用@PostMapping
5、编写代码(业务类)
@Service
public class ProductOrderServiceImpl implements ProductOrderService {
//注入
@Resource
private ProductClient productClient;
@Override
public ProductOrder save(int userId, int productId) {
//调用方法,返回是JSON对象
String result =productClient.findById(productId);
//将转化JsonNode对象
JsonNode jsonNode= JsonUtils.str2JsonNode(result);
/
//商品对象
ProductOrder po=new ProductOrder(UUID.randomUUID().toString(),new Date(),userId);
//获取数据
po.setProductName(jsonNode.get("name").toString());
po.setPrice(Integer.parseInt(jsonNode.get("price").toString()));
return po;
}
}
JsonUtils 类
/**
* json工具类
*/
public class JsonUtils {
private static final ObjectMapper objectMappper = new ObjectMapper();
/**
* json字符串转JsonNode对象的方法
*/
public static JsonNode str2JsonNode(String str){
try {
return objectMappper.readTree(str);
} catch (IOException e) {
return null;
}
}
}
6、启动(eureka,product 2个,order)
多次访问: http://localhost:8781/api/order/save?userId=1&productId=7