知其然还要知其所以然,在我们的生产项目上一般而言会部署多个微服务,每个微服务会负责不同版块的业务工作。如果某个微服务需要借助另外的某些微服务中的接口才能完成相应操作时,那么服务与服务之间就会存在相互调用的情况,远程服务调用因此油然而生!例如:跨数据库调用、设备对接等业务功能。
大伙开始接项目做的时候,都是单体项目开始做起的,也就是我们所说的SpringBoot框架,搞懂这个后才慢慢介入到微服务架构,也就是SpringCloud。SpringCloud简单点说就是多个SpringBoot拼凑而成的大家庭
,搞懂了单体,多个微服务架构也就不解自通了。
每个服务相关的接口流程就过多的阐述了,如果不清楚的小伙伴可以移步到我在此之前所撰写的简单开发的博文,这个基于SpringBoot_后端接口流程里面有详细的介绍。下面将通过相关项目实例介绍如何远程服务调用:
为了将所有跨远程服务调用的流程集中性进行管理,那么新开一个应用模块
相当有必要,在新开应用模块下汇集所有的远程服务及相关的实体类、服务熔断降级类及自动配置文件等。如下图所示:
创建远程服务的过程,其实就是将自己在某个服务中撰写的接口挪过来放在新开应用模块
下的某个Service下即可,而需要注意的点便是:@FeignClient注解
中要写明所对应的相关服务,以及“熔断降级”fallbackFactory所指明的类。
/**
* @InterfaceName: RemoteReportService
* @Description:
* @Author: YuHao
* @Date: 2023/06/07
*/
@FeignClient(contextId = "remoteReportService", value = "***相关应用服务名称", fallbackFactory = RemoteReportFallbackFactory.class)
public interface RemoteReportService {
@GetMapping("/clickReport/getRoadSectionTrafficReport")
R getRoadSectionTrafficReport(@RequestParam("beginDate") String beginDate, @RequestParam("endDate")String endDate,
@RequestParam("directionList") List<String> directionList, @RequestParam("roadSectionNameList")List<String> roadSectionNameList);
@GetMapping("/sa/getMainLineAndServiceAreaFlow")
R getMainLineAndServiceAreaFlow(@RequestParam("beginDate") String beginDate,@RequestParam("lineYearBeginDate") String lineYearBeginDate,@RequestParam("lineAllBeginDate") String lineAllBeginDate, @RequestParam("endDate")String endDate,@RequestParam("deviceIps") List<String> deviceIps,@RequestParam("gantryIds") List<String> gantryIds);
}
这一步的过程是防止某个被调取的服务挂掉了之后,去调用的服务还在不停地发送请求,进而发生雪崩等情况的出现。当服务请求不到时,该类的创建能发挥关键作用
,查询相关日志也能及时发现报错点
的位置。
/**
* @ClassName: RemoteReportFallbackFactory
* @Description:
* @Author: YuHao
* @Date: 2023/06/07
*/
@Component
@Slf4j
public class RemoteReportFallbackFactory implements FallbackFactory<RemoteReportService> {
@Override
public RemoteReportService create(Throwable cause) {
log.error("***报表获取暂无:{}", cause.getMessage());
return new RemoteReportService() {
@Override
public R getRoadSectionTrafficReport(String beginDate, String endDate, List<String> directionList, List<String> roadSectionNameList) {
return R.fail("****报表获取失败:" + cause.getMessage());
}
@Override
public R getMainLineAndServiceAreaFlow(String beginDate,String beginYearLineDate,String beginAllLineDate, String endDate, List<String> deviceIps, List<String> gantryIds) {
return R.fail("****报表获取失败:" + cause.getMessage());
}
};
}
}
spring.factories 配置文件是将 SpringBoot 包以外的 Bean注册到 SpringBoot 的 spring 容器中
。由于SpringBoot中的@Compone
ntScan 注解只能扫描 SpringBoot包内的 Bean 并注册到 spring 容器中,因此需借助
org.springframework.boot.autoconfigure.EnableAutoConfi
guration来注册SpringBoot包外的Bean。而 spring.factories 配置文件,则是用来记载SpringBoot包外需要注册的Bean的相关类名称。这个配置文件常常容易被忽视
,刚开始使用的时候,本人也常未将需要注册的类配置进来,导致我需要服务发现不了,导致远程服务不生效
。所以当前面的三个步骤完成以后,记得需要手动将需要的类型配置
进来。案例配置如下图所示:
在本服务中远程调用其他的指定服务,使用@Resource或者@Autowired自动注入
即可使用到指定服务的相关接口,而相关的调用过程如下实例所示,拿到返回的结果数据再进行相关的业务处理即可完成此服务模块Service层
的撰写。
//相关业务代码操作已省略...
@Resource/@Autowired
private RemoteReportService remoteReportService;
R<List<RoadSectionTrafficRep>> r = remoteReportService.getRoadSectionTrafficReport(beginDate, endDate, directionList, roadSectionNameList);
LinkedHashMap无法转成相关实体类,其实这个问题一般是会在远程调用服务中出现得较多
,可能因为返回格式
等问题导致最终无法转成我们所需的数据类型格式。
第一
需要声明好所返回的实体类,也就是说我们在R中要注明好泛型
,不然程序可能不好定位
返回的格式是什么类型的数据。
第二
参考Alibaba fastjson开源库
,前后端接口联调少不了的就是借用json
来打交道,因为json
是公认的标准的数据交换格式,fastjson
将常用的转换分析方式基本都包含(神器推荐!!!),相关分析转换方法如下实例代码所示:
public static final Object parse(String text); // 把JSON文本parse为JSONObject或者JSONArray
public static final JSONObject parseObject(String text); // 把JSON文本parse成JSONObject
public static final <T> T parseObject(String text, Class<T> clazz); // 把JSON文本parse为JavaBean
public static final JSONArray parseArray(String text); // 把JSON文本parse成JSONArray
public static final <T> List<T> parseArray(String text, Class<T> clazz); //把JSON文本parse成JavaBean集合
public static final String toJSONString(Object object); // 将JavaBean序列化为JSON文本
public static final String toJSONString(Object object, boolean prettyFormat); // 将JavaBean序列化为带格式的JSON文本
public static final Object toJSON(Object javaObject); //将JavaBean转换为JSONObject或者JSONArray。
在返回参数中写明泛型实体类,并参考fastjson开源库中相关的分析转换方法,即可快速解决此类问题
,相关实例代码如下所示:
@Override
public List<RoadSectionTrafficRep> getRoadSectionTraffic(String beginDate, String endDate, List<String> directionList, List<String> roadSectionNameList) {
R<List<RoadSectionTrafficRep>> r = remoteReportService.getRoadSectionTrafficReport(beginDate, endDate, directionList, roadSectionNameList);
List<RoadSectionTrafficRep> list = r.getData();
//list转成字符串
String jsonObject = JSON.toJSONString(list);
//json字符串再转成实体类
List<RoadSectionTrafficRep> roadSectionTrafficRepList = JSON.parseArray(jsonObject, RoadSectionTrafficRep.class); //把JSON文本parse成JavaBean集合
return roadSectionTrafficRepList;
}
路过的小伙伴,如果本篇博文对你的学习或者工作有所帮助,可以点赞+收藏+关注一波呀~小编后续每过一段时间会整理出相关项目实例的博文,感谢您的支持哦!!!✈️✈️✈️