本篇文章主要是记录了Feign的使用方式,并且重点讲述了使用Maven构建多模块项目,从而更好地适应微服务架构的软件开发模式。在服务调用的场景中,我们经常调用基于HTTP协议的服务,Feign封装了Http调用流程,更适合面向接口化的变成习惯。Feign底层使用了Ribbon作为负载均衡的客户端,而有关Ribbon的负载均衡的实现请见《RestTemplate与负载均衡器》。
一、Feign基本使用
1、引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、启动类注解
3、声明伪RPC调用接口(因为本质还是HTTP)
"SHOP-CLIENT") (name =
public interface ShopClient {
"/shop/show") (
String getShop();
}
4、注入接口对象并使用
"/order") (
public class OrderController {
private ShopClient shopClient;
public String getOrder(){
return shopClient.getShop();
}
}
使用Feign可以让调用者无感知这是一个远程调用,获得与本地方法一致的体验
二、项目多模块改造
其实多模块改造主要就是为了复用,毕竟让调用者去声明Client端是不合理的,Client应该由服务端声明,也就是我自己知道自己提供了哪些服务,别人来使用这些服务即可,而不是别人看我的源代码才知道我提供哪些接口。另外像接口输入参数,输出参数也都是需要为调用者提供的。
商品服务有两个功能:查看所有商品、新增商品,商品在数据库中的定义如下:
public class ShopInfo {
private String shopId;
private String shopName;
private Integer shopStock;
}
分别是商品ID、商品名称、商品库存等字段,我们需要给外界展示的是ID和名称,库存多少是没有必要展示费消费者的。同样的对于商城的管理系统来说,如果要添加新的商品,那么主键ID是没有必要让用户手动传入的,所以对于这两种情况分别就是此服务模块的输入参数和输出参数,分别定义对应的JavaBean:
public class ShopInfoInput {
private String shopName;
private Integer shopStock;
}
public class ShopInfoOutput {
private String shopId;
private String shopName;
}
并且将这两个类放到shop-common模块中,作为商品服务的通用模块。接下来是逻辑的编写,应该放到shop-serivce模块中,shop-service和我们平时的SpringBoot工程无区别,实现的都是主体业务逻辑:
"/shop") (
public class ShopController {
private static final List<ShopInfo> *list* = Arrays.*asList*(
new ShopInfo(UUID.*randomUUID*().toString(), "ThinkPad X1", 10),
new ShopInfo(UUID.*randomUUID*().toString(), "MacBook Air", 5),
new ShopInfo(UUID.*randomUUID*().toString(), "MacBook Pro", 20)
);
private static final CopyOnWriteArrayList<ShopInfo> *collect* = new CopyOnWriteArrayList<>(*list*);
"show") (
public List<ShopInfoOutput> getAllShop(){
return *collect*.stream()
.map(x -> new ShopInfoOutput(x.getShopId(), x.getShopName()))
.collect(Collectors.*toList*());
}
"create") (
public List<ShopInfoOutput> addOneShop(@RequestBody ShopInfoInput shopInfoInput){
*collect*.add(new ShopInfo(UUID.*randomUUID*().toString(), shopInfoInput.getShopName(), shopInfoInput.getShopStock()));
return *collect*.stream()
.map(x -> new ShopInfoOutput(x.getShopId(), x.getShopName()))
.collect(Collectors.*toList*());
}
}
class ShopInfo {
private String shopId;
private String shopName;
private Integer shopStock;
}
同时配置好Eureka,在application.yml中:
server:
port: 8080
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: shop-client
最后需要把服务提供暴露给外界使用,所以直接使用Feign来完成shop-client模块的编写:
"SHOP-CLIENT") (name =
public interface ShopClient {
"/shop/show") (
List<ShopInfoInput> getAllShop();
"/shop/create (