其实,在feign之前还有一个叫做Ribbon的东西,他们的原理都是rpc远程调用。
我们的教程不讲ribbon,只讲feign,因为feign其实就是对Robbon的一个封装,是现在大多数企业的选择。
1.物流模块
不多废话了,我们这一节来做一个物流模块,先干起来再说。
物流系统也要注册到eureka,属于一个eureka-client
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
因为用到了feign,所以要加这个依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
物流系统也是可以向外提供接口的,所以要加web依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
这样,基本的配置就ok了。
2.订单类和物流类
物流系统的作用,比如说可以获取订单列表,再生产物流单。那就需要订单的实体:
直接把订单系统的订单类拷贝过来即可。
再来一个物流类
/** * 物流单 */ public class Logistic { private Integer logisticId; //物流单ID private List<Integer> orderIds; //订单集合 private String date; //创建时间 public Integer getLogisticId() { return logisticId; } public void setLogisticId(Integer logisticId) { this.logisticId = logisticId; } public List<Integer> getOrderIds() { return orderIds; } public void setOrderIds(List<Integer> orderIds) { this.orderIds = orderIds; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } }
3.feign客户端
feign客户端就是一个用于rpc远程调用外部系统接口的桥梁,说太多专业术语没啥用,我们直接来看代码。
@FeignClient(value = "ORDER-DATA-SERVICE") public interface OrderFeignClient { @GetMapping("/order/list") public List<Order> queryOrders(); }
这是基于Spring Cloud Netflix开发的Feign客户端。
@FeignClient是一个注解,它用于定义一个Feign客户端。这个客户端是用来远程调用ORDER-DATA-SERVICE服务的。
value属性指定了被调用服务的名称,也就是ORDER-DATA-SERVICE。
OrderFeignClient是一个接口,用于定义客户端的请求方法。
在这个例子中,客户端定义了一个名为queryOrders的方法,该方法通过远程调用ORDER-DATA-SERVICE服务的/order/list接口来获取订单列表数据。
这个接口是使用HTTP GET方法请求的,List<Order>是该接口的返回值。
通过使用这个Feign客户端,可以方便地在微服务架构中进行服务之间的通信。
大家观察一下这个客户端,是不是特别像一个东西?
没错,是不是特别像controller啊。feign客户端就相当于是一个controller,用于调用其他服务的接口。
4.在哪里适用feign客户端
这个没有定论,不过我们一般是在service层中使用的。
@Service public class LogisticsServiceImpl implements LogisticsService{ @Autowired private OrderFeignClient orderFeignClient; @Override public void createLogisticsList() { List<Order> orders = orderFeignClient.queryOrders(); List<Integer> orderIds = orders.stream().map(Order::getOrderId).collect(Collectors.toList()); System.out.println(String.format("订单号:%s", orderIds)); Logistic logistic = new Logistic(); logistic.setLogisticId(1); logistic.setDate(DateUtil.now()); logistic.setOrderIds(orderIds); System.out.println(String.format("物流单:%s\n创建时间:%s", logistic.getLogisticId(),logistic.getDate())); } }
这是一个名为LogisticsServiceImpl的Spring Service实现类,该类实现了LogisticsService接口。这个服务用于创建物流单。在服务中,注入了一个名为orderFeignClient的OrderFeignClient客户端,用于远程调用ORDER-DATA-SERVICE服务获取订单列表数据。
在服务的createLogisticsList方法中,调用了orderFeignClient客户端的queryOrders方法获取订单数据,并使用Java 8的Stream API将订单列表转换为订单ID列表。
接下来,创建一个名为Logistic的物流实体,并将物流单号、创建时间和订单ID列表设置为物流实体的属性。最后,输出物流单的信息,包括物流单号、创建时间和订单ID列表。这个服务的作用是构建物流单信息,为后续的物流操作提供数据支持。
5. controller
@RestController public class LogisticController { @Autowired LogisticsService logisticsService; @GetMapping("/logistic/create") public String create() { logisticsService.createLogisticsList(); return "OK"; } }
这个类是一个基于Spring的REST服务控制器,使用@RestController注解进行标识,它提供了Web接口/logistic/create,该接口使用HTTP GET方法请求。请求的处理逻辑定义在create方法中,该方法通过依赖注入自动装配了一个名为logisticsService的LogisticsService服务,并调用服务的createLogisticsList方法创建物流单。最后返回一个OK字符串,表示创建物流单成功。通过调用这个Web接口,可以触发创建物流单的操作。
6. 启动类
物流微服务也是单体项目,需要独立部署,因为用到了feign,所以需要加上@EnableEurekaClient
,@EnableDiscoveryClient
,@EnableFeignClients
这三个注解。
@SpringBootApplication @EnableEurekaClient @EnableDiscoveryClient @EnableFeignClients public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
配置文件
spring: application: name: logistic-service eureka: client: serviceUrl: defaultZone: http://localhost:8081/eureka/
定义了应用程序的名称为logistic-service
。配置了Eureka的客户端,指定了Eureka服务注册中心的地址为http://localhost:8081/eureka/
。
最后,把服务都启动起来。
访问:http://localhost:8084/logistic/create
如果看到控制台打印出下面的内容,就说明调用成功了。