当前位置: 首页 > 后端技术 > Java

还在用Feign?推荐一款微服务间调用神器,与SpringCloud绝配!

时间:2023-04-01 14:20:16 Java

在微服务项目中,如果我们要实现服务之间的调用,我们通常会选择Feign。介绍了Retrofit,一个HTTP客户端工具,配合SpringBoot非常好用!事实上,Retrofit不仅支持普通的HTTP调用,还支持微服务之间的调用,可以实现负载均衡和熔断限流。今天给大家介绍一下SpringCloudAlibaba下Retrofit的使用,希望对大家有所帮助!SpringBoot实战电商项目商城(50k+star)地址:https://github.com/macrozheng/mall前置知识本文主要介绍SpringCloudAlibaba下Retrofit的使用,需要Nacos和Sentinel。太熟悉的朋友可以先参考上一篇。SpringCloudAlibaba:Nacos使用SpringCloudAlibaba作为注册中心和配置中心:Sentinel还在用HttpUtil实现熔断限流?试试这个优雅的HTTP客户端工具,它与SpringBoot是绝配!构建在使用之前,我们需要先构建Nacos和Sentinel,然后准备一个被调用的服务,使用之前的nacos-user-service即可。首先从官网下载Nacos,这里是nacos-server-1.3.0.zip文件,下载地址:https://github.com/alibaba/na...解压安装包到指定目录,运行直接在bin目录下Startup.cmd,运行成功后访问Nacos,账号密码是nacos,访问地址:http://localhost:8848/nacos接下来从官网下载Sentinel,这里是sentinel-dashboard-1.6.3.jar文件,下载地址:https://github.com/alibaba/Se...下载完成后,输入以下命令运行Sentinel控制台;java-jarsentinel-dashboard-1.6.3.jarSentinel控制台默认在端口8080上运行。登录账号密码为sentinel,可通过以下地址访问:http://localhost:8080接下来启动nacos-user-service服务,其中包含了User对象的CRUD操作接口。启动成功后,会在Nacos中注册。/***宏创建于2019/8/29。*/@RestController@RequestMapping("/user")publicclassUserController{privateLoggerLOGGER=LoggerFactory.getLogger(this.getClass());@Autowired私有用户服务用户服务;@PostMapping("/create")publicCommonResultcreate(@RequestBodyUseruser){userService.create(user);returnnewCommonResult("操作成功",200);}@GetMapping("/{id}")publicCommonResultgetUser(@PathVariableLongid){Useruser=userService.getUser(id);LOGGER.info("根据id获取用户信息,用户名为:{}",user.getUsername());返回新的CommonResult<>(用户);}@GetMapping("/getUserByIds")publicCommonResult>getUserByIds(@RequestParamListids){ListuserList=userService.getUserByIds(ids);记录器。info("根据ids获取用户信息,用户列表为:{}",userList);返回新的CommonResult<>(userList);}@GetMapping("/getByUsername")publicCommonResultgetByUsername(@RequestParamStringusername){Useruser=userService.getByUsername(username);返回新的CommonResult<>(用户);}@PostMapping("/update")publicCommonResultupdate(@RequestBodyUseruser){userService.update(user);returnnewCommonResult("操作成功",200);}@PostMapping("/delete/{id}")publicCommonResultdelete(@PathVariableLongid){userService.delete(id);returnnewCommonResult("操作成功",200);}}使用接下来介绍一下Retrofit的基本使用,包括服务间调用、服务限流和熔断降额集成配置首先在pom.xml中添加Nacos、Sentinel、Retrofit相关依赖;com.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoverycom.alibaba.cloudspring-cloud-starter-alibaba-sentinelcom.github.lianjiatechretrofit-spring-boot-starter2.2.18然后在application.yml中配置Nacos、Sentinel和Retrofit,并在Retrofit中配置日志和开启熔断降级;服务器:端口:8402spring:应用程序:名称:nacos-retrofit-service云:nacos:发现:server-addr:localhost:8848#配置Nacos地址sentinel:transport:dashboard:localhost:8080#配置sentineldashboard地址port:8719retrofit:log:#启用日志打印enable:true#日志打印拦截器logging-interceptor:com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor#全局日志打印级别global-log-level:info#全局日志打印策略global-log-strategy:body#熔断降级配置degrade:#是否开启熔断降级enable:true#Fuse降级实现??方法degrade-type:sentinel#Fuse资源名称解析器resource-name-parser:com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser添加一个RetrofitJava配置,配置并选择一个服务实例Bean能/***Retrofit相关配置*宏创建于2022/1/26。*/@ConfigurationpublicclassRetrofitConfig{@Bean@AutowiredpublicServiceInstanceChooserserviceInstanceChooser(LoadBalancerClientloadBalancerClient){返回新的SpringCloudServiceInstanceChooser(loadBalancerClient);服务间调用}}Retrofit在微服务间调用非常简单,直接使用@RetrofitClient注解,将serviceId设置为要调用的服务ID即可;/***定义调用远程User服务的Http接口*宏创建于2019/9/5。*/@RetrofitClient(serviceId="nacos-user-service",fallback=UserFallbackService.class)publicinterfaceUserService{@POST("/user/create")CommonResultcreate(@BodyUseruser);@GET("/user/{id}")CommonResultgetUser(@Path("id")Longid);@GET("/user/getByUsername")CommonResultgetByUsername(@Query("username")Stringusername);@POST("/user/update")CommonResultupdate(@BodyUseruser);@邮政(”/user/delete/{id}")CommonResultdelete(@Path("id")Longid);}我们可以启动2个nacos-user-service服务和1个nacos-retrofit-service服务,此时Nacos注册了center显示如下;然后通过Swagger测试,调用接口获取用户详情,发现可以成功返回远程数据,访问地址:http://localhost:8402/swagger...查看nacos打印的日志-retrofit-service服务,交替打印两个实例的请求调用,我们可以发现Retrofit可以通过配置serviceId实现微服务间的调用和负载均衡服务限流Retrofit的限流功能基本依赖于Sentinel,与直接使用Sentinel没有区别。我们创建一个测试类RateLimitController来试试它的限流功能;/***限流功能*macro于2019/11/7创建。*/@Api(tags="RateLimitController",description="限速功能")@RestController@RequestMapping("/rateLimit")publicclassRateLimitController{@ApiOperation("通过资源名限速,需要指定限速处理逻辑")@GetMapping("/byResource")@SentinelResource(value="byResource",blockHandler="handleException")publicCommonResultbyResource(){returnnewCommonResult("按资源名称限制",200);}@ApiOperation("通过URL限制,默认限流处理逻辑")@GetMapping("/byUrl")@SentinelResource(value="byUrl",blockHandler="handleException")publicCommonResultbyUrl(){returnnewCommonResult("url的当前限制",200);}@ApiOperation("自定义通用限流处理逻辑")@GetMapping("/customBlockHandler")@SentinelResource(value="customBlockHandler",blockHandler="handleException",blockHandlerClass=CustomBlockHandler.class)publicCommonResultblockHandler(){returnnewCommonResult("限流成功",200);}publicCommonResulthandleException(BlockExceptionexception){returnnewCommonResult(exception.getClass().getCanonicalName(),200);}}接下来在Sentinel控制台创建规则,根据资源名限流;那么当我们以较快的速度访问接口时,就会触发限流,返回如下信息断路器降级Retrofit的断路器降级功能基本依赖于Sentinel,我们创建一个测试类CircleBreakerController来尝试其断路器降级功能;/***断路器降级*由macro创建于2019/11/7。*/@Api(tags="CircleBreakerController",description="Fusedowngrade")@RestController@RequestMapping("/breaker")publicclassCircleBreakerController{privateLoggerLOGGER=LoggerFactory.getLogger(CircleBreakerController.class);@AutowiredprivateUserService用户服务;@ApiOperation("熔断降级")@RequestMapping(value="/fallback/{id}",method=RequestMethod.GET)@SentinelResource(value="fallback",fallback="handleFallback")publicCommonResultfallback(@PathVariableLongid){返回userService.getUser(id);}@ApiOperation("忽略断路器降级异常")@RequestMapping(value="/fallbackException/{id}",method=RequestMethod.GET)@SentinelResource(value="fallbackException",fallback="handleFallback2",exceptionsToIgnore={NullPointerException.class})publicCommonResultfallbackException(@PathVariableLongid){if(id==1){thrownewIndexOutOfBoundsException();}elseif(id==2){thrownewNullPointerException();}返回userService.getUser(id);}publicCommonResulthandleFallback(Longid){UserdefaultUser=newUser(-1L,"defaultUser","123456");returnnewCommonResult<>(defaultUser,"Servicefallbackreturn",200);}publicCommonResulthandleFallback2(@PathVariableLongid,Throwablee){LOGGER.error("handleFallback2id:{},throwableclass:{}",id,e.getClass());用户defaultUser=newUser(-2L,"defaultUser2","123456");returnnewCommonResult<>(defaultUser,"从服务降级返回",200);}}由于我们在nacos-user-service中没有定义id为4的用户,调用时会产生异常,所以访问下面的接口会返回服务降级的结果,返回我们默认的用户信息综上所述,Retrofit给了我们除了Feign和Dubbo之外的第三种微服务间调用的选择,使用起来非常方便。记得之前在使用Feign的过程中,实现者的Controller往往要提取一个接口,方便调用者实现调用。接口实现者和调用者之间的耦合度非常高。如果当时使用Retrofit,这种情况会得到很大的改善。总的来说,Retrofit为我们提供了一种更优雅的调用HTTP的方式,不仅在单体应用中,在微服务应用中也是如此!参考官方文档:https://github.com/LianjiaTec...项目源码地址https://github.com/macrozheng...