In a microservice project, if we want to implement inter-service calls, Feign is generally chosen. I introduced an HTTP client toolRetrofit
, which is very easy to use with SpringBoot! In fact,Retrofit
not only supports ordinary HTTP calls, but also supports calls between microservices, load balancing and fuse current limiting can be achieved. Today we will introduce the use ofRetrofit
under Spring Cloud Alibaba, I hope it will be helpful to you!
SpringBoot actual e-commerce project mall (50k+star) address: https://github.com/macrozheng/mall
Pre-knowledge
This article mainly introduces the use of Retrofit under Spring Cloud Alibaba, which requires the use of Nacos and Sentinel. Those who are not familiar with these technologies can refer to the previous articles first.
- Spring Cloud Alibaba: Nacos uses as the registration center and configuration center
- Spring Cloud Alibaba: Sentinel implements fuse and current
- Still using HttpUtil? Try this elegant HTTP client tool, perfect for SpringBoot!
build
Before using it, we need to build Nacos and Sentinel first, and then prepare a called service, just use the previous nacos-user-service
.
- First download Nacos from the official website, here is the
nacos-server-1.3.0.zip
file, download address: https://github.com/alibaba/nacos/releases
- Unzip the installation package to the specified directory, directly run
bin
in thestartup.cmd
directory, and access Nacos after successful operation. The account and password arenacos
- Next, download Sentinel from the official website, here is the
sentinel-dashboard-1.6.3.jar
file, download address: https://github.com/alibaba/Sentinel/releases
- After the download is complete, enter the following command to run the Sentinel console;
java -jar sentinel-dashboard-1.6.3.jar
- Sentinel console runs on port
8080
by default, and the login account password issentinel
, which can be accessed through the following address: http://localhost:8080
- Next, start the
nacos-user-service
service, which contains the CRUD operation interface for the User object. After the startup is successful, it will be registered in Nacos.
/**
* Created by macro on 2019/8/29.
*/
@RestController
@RequestMapping("/user")
public class UserController {
private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
@Autowired
private UserService userService;
@PostMapping("/create")
public CommonResult create(@RequestBody User user) {
userService.create(user);
return new CommonResult("操作成功", 200);
}
@GetMapping("/{id}")
public CommonResult<User> getUser(@PathVariable Long id) {
User user = userService.getUser(id);
LOGGER.info("根据id获取用户信息,用户名称为:{}",user.getUsername());
return new CommonResult<>(user);
}
@GetMapping("/getUserByIds")
public CommonResult<List<User>> getUserByIds(@RequestParam List<Long> ids) {
List<User> userList= userService.getUserByIds(ids);
LOGGER.info("根据ids获取用户信息,用户列表为:{}",userList);
return new CommonResult<>(userList);
}
@GetMapping("/getByUsername")
public CommonResult<User> getByUsername(@RequestParam String username) {
User user = userService.getByUsername(username);
return new CommonResult<>(user);
}
@PostMapping("/update")
public CommonResult update(@RequestBody User user) {
userService.update(user);
return new CommonResult("操作成功", 200);
}
@PostMapping("/delete/{id}")
public CommonResult delete(@PathVariable Long id) {
userService.delete(id);
return new CommonResult("操作成功", 200);
}
}
use
Next, let's introduce the basic use of Retrofit, including inter-service calls, service current limiting, and circuit breaker downgrade.
Integration and configuration
- First add Nacos, Sentinel and Retrofit related dependencies in
pom.xml
;
<dependencies>
<!--Nacos注册中心依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--Sentinel依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--Retrofit依赖-->
<dependency>
<groupId>com.github.lianjiatech</groupId>
<artifactId>retrofit-spring-boot-starter</artifactId>
<version>2.2.18</version>
</dependency>
</dependencies>
- Then configure Nacos, Sentinel and Retrofit in
application.yml
, log and enable fuse downgrade under Retrofit configuration;
server:
port: 8402
spring:
application:
name: nacos-retrofit-service
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos地址
sentinel:
transport:
dashboard: localhost:8080 #配置sentinel dashboard地址
port: 8719
retrofit:
log:
# 启用日志打印
enable: true
# 日志打印拦截器
logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor
# 全局日志打印级别
global-log-level: info
# 全局日志打印策略
global-log-strategy: body
# 熔断降级配置
degrade:
# 是否启用熔断降级
enable: true
# 熔断降级实现方式
degrade-type: sentinel
# 熔断资源名称解析器
resource-name-parser: com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser
- Add a Retrofit Java configuration, and configure the bean that selects the service instance.
/**
* Retrofit相关配置
* Created by macro on 2022/1/26.
*/
@Configuration
public class RetrofitConfig {
@Bean
@Autowired
public ServiceInstanceChooser serviceInstanceChooser(LoadBalancerClient loadBalancerClient) {
return new SpringCloudServiceInstanceChooser(loadBalancerClient);
}
}
inter-service call
- It is very simple to use Retrofit to call between microservices, directly use the
@RetrofitClient
annotation, and setserviceId
as the ID of the service to be called;
/**
* 定义Http接口,用于调用远程的User服务
* Created by macro on 2019/9/5.
*/
@RetrofitClient(serviceId = "nacos-user-service", fallback = UserFallbackService.class)
public interface UserService {
@POST("/user/create")
CommonResult create(@Body User user);
@GET("/user/{id}")
CommonResult<User> getUser(@Path("id") Long id);
@GET("/user/getByUsername")
CommonResult<User> getByUsername(@Query("username") String username);
@POST("/user/update")
CommonResult update(@Body User user);
@POST("/user/delete/{id}")
CommonResult delete(@Path("id") Long id);
}
- We can start 2
nacos-user-service
services and 1nacos-retrofit-service
service, and the Nacos registration center displays as follows;
- Then test through Swagger, call the interface for obtaining user details, and find that the remote data can be successfully returned. Access address: http://localhost:8402/swagger-ui/
- Looking at the logs printed by the
nacos-retrofit-service
service, the request calls of the two instances are printed alternately. We can find that Retrofit can implement calls and load balancing between microservices by configuringserviceId
.
Service current limit
- Retrofit's current limiting function basically relies on Sentinel, which is no different from using Sentinel directly. We create a test class
RateLimitController
to try its current limiting function;
/**
* 限流功能
* Created by macro on 2019/11/7.
*/
@Api(tags = "RateLimitController",description = "限流功能")
@RestController
@RequestMapping("/rateLimit")
public class RateLimitController {
@ApiOperation("按资源名称限流,需要指定限流处理逻辑")
@GetMapping("/byResource")
@SentinelResource(value = "byResource",blockHandler = "handleException")
public CommonResult byResource() {
return new CommonResult("按资源名称限流", 200);
}
@ApiOperation("按URL限流,有默认的限流处理逻辑")
@GetMapping("/byUrl")
@SentinelResource(value = "byUrl",blockHandler = "handleException")
public CommonResult byUrl() {
return new CommonResult("按url限流", 200);
}
@ApiOperation("自定义通用的限流处理逻辑")
@GetMapping("/customBlockHandler")
@SentinelResource(value = "customBlockHandler", blockHandler = "handleException",blockHandlerClass = CustomBlockHandler.class)
public CommonResult blockHandler() {
return new CommonResult("限流成功", 200);
}
public CommonResult handleException(BlockException exception){
return new CommonResult(exception.getClass().getCanonicalName(),200);
}
}
- Next, in the Sentinel console, create a rule to limit the current based on the
resource name;
- Later, when we access the interface at a faster speed, the current limit will be triggered, and the following information will be returned.
Fusing downgrade
- The fuse downgrade function of Retrofit also basically depends on Sentinel. We created a test class
CircleBreakerController
to try its fuse downgrade function;
/**
* 熔断降级
* Created by macro on 2019/11/7.
*/
@Api(tags = "CircleBreakerController",description = "熔断降级")
@RestController
@RequestMapping("/breaker")
public class CircleBreakerController {
private Logger LOGGER = LoggerFactory.getLogger(CircleBreakerController.class);
@Autowired
private UserService userService;
@ApiOperation("熔断降级")
@RequestMapping(value = "/fallback/{id}",method = RequestMethod.GET)
@SentinelResource(value = "fallback",fallback = "handleFallback")
public CommonResult fallback(@PathVariable Long id) {
return userService.getUser(id);
}
@ApiOperation("忽略异常进行熔断降级")
@RequestMapping(value = "/fallbackException/{id}",method = RequestMethod.GET)
@SentinelResource(value = "fallbackException",fallback = "handleFallback2", exceptionsToIgnore = {NullPointerException.class})
public CommonResult fallbackException(@PathVariable Long id) {
if (id == 1) {
throw new IndexOutOfBoundsException();
} else if (id == 2) {
throw new NullPointerException();
}
return userService.getUser(id);
}
public CommonResult handleFallback(Long id) {
User defaultUser = new User(-1L, "defaultUser", "123456");
return new CommonResult<>(defaultUser,"服务降级返回",200);
}
public CommonResult handleFallback2(@PathVariable Long id, Throwable e) {
LOGGER.error("handleFallback2 id:{},throwable class:{}", id, e.getClass());
User defaultUser = new User(-2L, "defaultUser2", "123456");
return new CommonResult<>(defaultUser,"服务降级返回",200);
}
}
- Since we did not define the user
id is 4 in
nacos-user-service
, an exception will occur during the calling process, so accessing the following interface will return the service downgrade result and return our default user information.
Summarize
Retrofit gives us a third choice of calling between microservices besides Feign and Dubbo, which is very convenient to use. I remember that in the process of using Feign before, the controller of the implementer often had to extract an interface to facilitate the caller to implement the call, and the interface implementer and the caller had a high degree of coupling. This situation would have been greatly improved if Retrofit had been used at the time. In general, Retrofit provides us with a more elegant way of making HTTP calls, not only in monolithic applications, but also in microservice applications!
References
Official document: https://github.com/LianjiaTech/retrofit-spring-boot-starter
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。