1. 微服务之间内部调用实现方法介绍
在系列三业务领域驱动微服务设计的文章中,我们初步划分了三个领域:身份认证限界上下文、打车管理限界上下文、运营报表限界上下文。其中运营报表限界上下文是打车管理上下文的下游。这意味着在落地中,运营报表微服务要调用打车管理微服务提供的接口,来统计业务数据,生成运营报表,运营报表微服务是打车管理微服务的内部消费者。
在微服务的开发中,我们还会碰到很多微服务之间内部相互调用的情况,特别是对数据服务的调用。在Spring Cloud中,有两种方式可以,一种是使用RestTemplate,另一种是使用Feign框架。
RestTemplate调用另一个微服务的接口我们在系列五负载均衡的文章中已经讲过具体的实现,本章不再累述。
Feign是声明式Web服务客户端,所谓声明式,指的是在代码中,将要调用的其它内部微服务提供的Restful API声明为自己的接口,该接口使用FeignClient注解。声明后,在本微服务中就可以通过接口注入的方式消费其它微服务的提供的Restful API了。
Feign也内置有负载均衡Ribbon,会采用轮训式的负载均衡方式。
2. 代码实现及验证
本次代码实现模拟两个场景:通过Feign实现内部调用;通过Feign实现负载均衡的内部调用;
2.1 新建一个项目:
在start.spring.io里新建一个名为“reports”的项目,在依赖项里额外增加对feign的依赖,下载并将该项目导入到NetBeans里。
2.2 通过Feign实现内部调用
1) 在主程序除添加@EnableEurekaClient注解外,同时添加@EnableFeignClients注解。@EnableFeignClients注解用于开启Feign的功能
2) 配置Feign Clients项目的属性,端口设为2266,微服务的名称为reporting-service,reporting-service和其它微服务一样注册在端口号为1111的Eureka Server上。具体配置如下所示:
3) 在BOOKINGCAR-SERVICE微服务的OrderController包里,新建一个数据服务的接口getOrderName,该接口通过Order ID来获取订单名称
4) 在REPORTING-SERVICE项目下新建一个package,名为"com.accenture.j2c.bookingcar.reports.clientinterface",在该package下新建一个OrderClient接口,在该接口里会将BOOKINGCAR-SERVICE提供的getOrderName的restful API声明为REPORTING-SERVICE里的OrderClient接口里的一个方法。
具体实现可以分为两步:
第一步:通过FeignClient注解,首先到Eureka Server找到名字为“BOOKINGCAR-SERVICE"的微服务;
第二步:使用RequestMapping注解声明BOOKINGCAR-SERVICE微服务提供的getOrderName的Restful API的入口, getOrderName的入口为”{BOOKINGCAR-SERVICE}/v1/order/name/{id}"。
代码如下:
5) 在REPORTING-SERVICE项目下新建一个Rest Controller的package,名字为“com.accenture.j2c.bookingcar.reports.controller”,在该包下新建一个OrderController类,注入REPORTING-SERVICE下的OrderClient接口,新建一个feign_getOrderName接口,在该接口里通过调用OrderClient接口中的getOrderName的方法实现对BOOKINGCAR-SERVICE微服务中getOrderName的Restful API接口的调用,代码如下:
6) 验证
启动Eureka Server, BOOKINGCAR-SERVICE, REPORTING-SERVICE,打开Eureka注册中心,显示如下:
BOOKINGCAR-SERVICE和REPORTINGCAR-SERVICE这两个微服务都已经启动,其中BOOKINGCAR-SERVICE的接口为2227,REPORTING-SERVICE微服务的端口为2266。
点击BOOKIGNCAR-SERVICE后提供的链接,输入请求参数“v1/order/name/1",获得id为1的订单名称
点击REPORTING-SERVICE后的提供的链接,输入请求参数“v1/order/1",结果为:
我们发现REPORTING-SERVICE里的结果同BOOKINGCAR-SERVICE里的结果保持一致,这说明了REPORTING-SERVICE已经能调用另一微服务BOOKINGCAR-SERVICE里开放的接口。
2.3 通过Feign实现内部调用的负载均衡
1) 在REPORTING-SERVICE的"com.accenture.j2c.bookingcar.reports.clientinterface"包下,新建一个接口LBTestClient,在该接口里会将BOOKINGCAR-SERVICE提供的findServicePort的restful API声明为REPORTING-SERVICE里的LBTestClient接口里的一个方法。BOOKINGCAR-SERVICE里的findServiceReport接口在之前已经定义好,本次示例继续使用该接口:
REPORTING-SERVICE里的LBTestClient接口声明如下:
2) 在REPORTING-SERVICE里的“com.accenture.j2c.bookingcar.reports.controller“包下,新建一个类LBTestController,在该控制器类中注入LBTestClient接口,新建一个feign_getPort接口,在该接口里通过调用LBTestClient接口中的方法实现对BOOKINGCAR-SERVICE微服务中findServicePort的Restful API接口的调用,代码如下:
3) 验证:
重新启动一个端口号为2228的BOOKINGCAR-SERVICE微服务实例,启动后,在EUREKA注册中心可以看到BOOKINGCAR-SERVICE有两个实例在运行,端口号分别为2227和2228,见下图:
点击REPORTING-SERVICE后提供的链接,输入负载均衡验证的参数"v1/port",运行后显示结果如下:
再次运行,结果如下:
上面结果验证了Feign内置的Ribbon负载均衡已经发挥作用
3. 总结
在Spring Cloud里,微服务之间的相互调用可以通过RestTemplate和Feign两种方式实现。Feign同时内置了Ribbon负载均衡,代码更加清晰,推荐使用Feign来实现微服务间的相互调用。
代码:https://github.com/shuxingliu/microservices
利用Spring Cloud实现微服务(四)- 微服务实现与注册
利用Spring Cloud实现微服务(三)- 业务领域驱动微服务设计