RestTemplate存在问题:
虽然说RestTemplate对HTTP封装后,已经比直接使用HTTPClient简单方便多了,但是还是存在一些问题:
1,需要拼接URL,灵活性高,但是封装繁琐,如果URL复杂时,容易出错
2.代码可读性差,风格不统一
微服务之间的通信方式,通常有两种:RPC和HTTP
在SpringCloud中,默认是使用HTTP来进行微服务的通信,最常用的实现形式有两种:1.RestTemplate 2.OpenFeign
ps:RPC(Remote Procedure Call)远程过程调用,是一种网络从远程计算机上请求服务,而不需要了解底层网络通信细节,RPC可以使用多种网络协议进行通信,如HTTP,TCP,UDP等,并且在TCP/IP网络四层模型中跨越了传输层和应用层,简言之RPC就像调用本地方法一样调用远程方法
OpenFeign介绍
OpenFeign是一个声明式WebService客户端,他让微服务之间的调用变得更简单,类似Controller调用Service,只需要创建一个接口,然后添加注解就可以使用OpenFeign
OpenFeign的前身是Feign Feign是Netflix公司开源的一个组件
可以理解为Netflix Feign是OpenFeign的祖先,或者说OpenFeign是Netflix Feign的升级版
SpringCloudFeign
SpringCloudFeign是Spring对Feign的封装,将Feign项目集成到SpringCloud生态系统中,受Feign更名影响,SpringCloudFeign也有两个starter:1.spring-cloud-starter-feign 2.spring-cloud-starter-openfeign
OpenFeign快速上手
1.引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.通过注解,开启Feign的功能
在订单服务(要调用某个module)的启动类加上@EnableFeignClients的注解,表示开启OpenFeign的功能
3.编写客户端
基于SpringMVC的注解来声明远程他用的信息
java
@FeignClient(value = "product-service")
public interface ProductAPI{
@RequestingMapping("/product/{productId}")
ProductInfo getProductInfo(@PathVariable("productId") Integer productId);
}
也可以使用@FeignClient(Path="/product")表示feign客户端的统一前缀
4.修改远程调用
java
@Autowired
private ProductApi productApi;
public OrderInfo selectOrderById(Integer orderId){
OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
ProductInfo productInfo = productApi.getProductById(orderInfo.getProductId());
orderInfo.setProductInfo(productInfo);
return orderInfo;
}
5.进行测试
启动服务访问接口,测试远程调用会发现,使用feign也可以实现远程调用
Feign简化了与HTTP服务交互的过程,把REST客户端的定义转换为JAVA接口,并通过注解的方式来声明请求参数等信息,使远程调用更加方便
OpenFeign参数传递
1.传递单个参数
要用@RequestParam做参数绑定,这是不能忽略的
服务提供方product-service
java
@RequestMapping("/product")
@RestController
public class ProductController{
@RequesMapping("/p1)
public String p1(Integer id){
return "p1接受到参数:"+id;
}
}
Feign客户端
java
@FeignClient(value="product-service",path="/product)
public interface ProductApi{
@RequestMapping("/p1)
String p1(@RequestParam("id")Integer id)
}
服务消费方
java
@RequestMapping("/feign)
@RestController
public class FeignController{
@Autowired
private ProductApi productApi;
@RequestMapping("o1")
public String o1(Integer id){
return productApi.p1(id);
}
}
测试远程调用

2.传递多个参数
使用多个@RequestParam进行参数绑定即可
服务提供方
java
@RequestMapping("/product")
@RestController
public class ProductController{
@RequesMapping("/p2)
public String p2(Integer id,String name){
return "p2接受到参数:"+id+ " "+name;
}
}
Feign客户端
java
@FeignClient(value="product-service",path="/product)
public interface ProductApi{
@RequestMapping("/p2)
String p2(@RequestParam("id")Integer id @RequestParam("name")String name)
}
服务消费方
java
@RequestMapping("/feign)
@RestController
public class FeignController{
@Autowired
private ProductApi productApi;
@RequestMapping("o2")
public String o1(Integer id,String name){
return productApi.p2(id,name);
}
}

3,传递对象
服务提供方
java
@RequestMapping("/product")
@RestController
public class ProductController{
@RequesMapping("/p3)
public String p2(ProductInfo productInfo){
return "接受到对象,productInfo:"+productInfo;
}
}
Feign客户端
java
@FeignClient(value="product-service",path="/product)
public interface ProductApi{
@RequestMapping("/p3)
String p3(@SpringQueryMap ProductInfo productInfo);
}
服务消费方
java
@RequestMapping("/o3")
public String o3(){
ProductInfo productInfo = new ProductInfo();
productInfo.setId(45);
productInfo.setProductName("T恤");
return productApi.p3(productInfo);
}
4.传递JSON
feign客户端在传递参数的时候加上@RequestBody即可
OpenFeign的最佳实现
1.继承
可以把一个常见的操作封装到接口里,我们定义好一个接口,服务提供实现这个接口,服务消费方编写Feign接口的时候,直接继承这个接口
2.抽取的方式
官方推荐的方式为继承的方式,但是企业开发的时候更多的是把Feign接口抽取为一个独立的模块(做法和继承相似但理念不同)
将Feign抽取为要给独立的模块,并把涉及到的实体类等都放在一个模块中,打成一个jar包,服务消费方只需要依赖该jar包即可