Feign 的远程调用
之前的系统结构是浏览器直接访问后台服务
后面我们通过一个Demo项目演示 Spring Cloud 远程调用
实战案列
添加 Feign,用Feign的声明式客户端接口做远程调用
-
pom.xml 添加 Feign 依赖
-
启动类添加注解:
@EnableFeignClients
-
定义两个客户端接口:ItemClient 、 UserClient
-
修改 OrderServiceImpl 完成远程的调用
通过 Sp04Order 订单服务调用 Sp02Item 商品和 Sp03User 用户服务。
pom.xml
sp04-orderservice 模块中添加 Feign 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
主程序
启动类添加注解: @EnableFeignClients
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class Sp04OrderserviceApplication {
public static void main(String[] args) {
SpringApplication.run(Sp04OrderserviceApplication.class, args);
}
}
定义两个客户端接口
配置三条规则:
- 调用哪个服务
- 调用哪个路径
- 向路径提交什么参数
ItemClient
package cn.tedu.sp04.feign;
import cn.tedu.sp01.pojo.Item;
import cn.tedu.sp01.util.JsonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
@FeignClient(name = "item-service")
public interface ItemClient {
@GetMapping("/{orderId}")
JsonResult<List<Item>> getItems(@PathVariable String orderId);
@PostMapping("/decreaseNumber")
JsonResult<?> decreaseNumber(@RequestBody List<Item> items);
}
UserClient
package cn.tedu.sp04.feign;
import cn.tedu.sp01.pojo.User;
import cn.tedu.sp01.util.JsonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/{userId}")
JsonResult<User> getUser(@PathVariable Integer userId);
@GetMapping("/{userId}/score")// /8/score?score=1000
JsonResult<?> addScore(
@PathVariable Integer userId,
@RequestParam("score") Integer score);
}
OrderServiceImpl
修改 OrderServiceImpl 完成远程的调用
package cn.tedu.sp04.serivce;
import cn.tedu.sp01.pojo.Item;
import cn.tedu.sp01.pojo.Order;
import cn.tedu.sp01.pojo.User;
import cn.tedu.sp01.service.OrderService;
import cn.tedu.sp01.util.JsonResult;
import cn.tedu.sp04.feign.ItemClient;
import cn.tedu.sp04.feign.UserClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author deven
* @version 1.0
* @description: TODO
* @date 2021/10/18 15:51
*/
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private ItemClient itemClient;
@Autowired
private UserClient userClient;
/**
* @description: 获取订单信息
* 同时远程调用 itemClient 服务,获取商品列表
* 远程调用 userClient 服务,获取用户数据
* @author deven
* @date 2021/10/19 20:47
* @version 1.0
*/
@Override
public Order getOrder(String orderId) {
log.info("获取订单,orderId="+orderId);
// 远程调用商品,获取商品列表
JsonResult<List<Item>> items = itemClient.getItems(orderId);
// 远程调用用户,获取用户数据
JsonResult<User> user = userClient.getUser(8);// 真实项目中要获取已登录用户的id
Order order = new Order();
order.setId(orderId);
order.setUser(user.getData());
order.setItems(items.getData());
return order;
}
/**
* @description: 添加订单信息
* 下单成功会远程调用 itemClient 服务实现减少商品库存,
* 远程调用 uerClient 服务增加用户订单
* @author deven
* @date 2021/10/19 13:17
* @version 1.0
*/
@Override
public void addOrder(Order order) {
log.info("添加订单:"+order);
// 远程调用商品,减少库存
itemClient.decreaseNumber(order.getItems());
// 远程调用用户,增加积分
userClient.addScore(order.getUser().getId(), 1000);
}
}
访问测试
访问测试,Feign 会把请求分发到 8001 和 8002 两个服务端口上
http://localhost:8201/34
第一次访问,sp02item-8001 响应
第二次访问,sp02item-8002 响应
Feign 的负载均衡
实战案列
Feign 的调用重试
远程调用失败,可以自动发起重试调用
-
异常
-
服务器宕机
-
后台服务阻塞超时
重试参数: -
MaxAutoRetries - 单台服务器的重试次数,模式0
-
MaxAutoRetriesNextServer - 更换服务器的次数,默认1
-
ReadTimeout - 等待响应的超时时间,默认1000
-
OkToRetryOnAllOperations - 是否对所有类型请求都重试,默认只对GET请求重试
-
ConnectTimeout - 与后台服务器建立连接的等待超时时间,默认1000