公司项目中经常会有涉及到各个服务之间的调用,最开始都是使用HttpClient进行管理。最初的时候这种做法没有什么问题,可是随着用户体量变大,服务的增多,逐渐暴露不足之处。
- 大量的uri信息需要配置
- 无法实现服务之间的负载均衡
最开始的想法是使用OpenFeign解决该现象,后来无意中发现Retrofit这个组件。它与OpenFeign的使用方法大体一致,都能够解决微服务场景下:服务自动发现、服务负载均衡、服务降级等要求。
Retrofit集成
在maven的pom文件中引入retrofi-spring-boot-starter
<dependency>
<groupId>com.github.lianjiatech</groupId>
<artifactId>retrofit-spring-boot-starter</artifactId>
<version>2.3.7</version>
</dependency>
自动化配置
@Configuration
public class RetrofitConfig {
/***
*
* 这里是配合rabbion实现负载均衡策略
**/
@Autowired
private LoadBalancerClient loadBalancerClient;
@Bean
public ServiceInstanceChooser serviceInstanceChooser() {
return new SpringCloudServiceInstanceChooser(loadBalancerClient);
}
}
客户端声明
客户端声明支持两种方式,一种是非微服务体系,一种是微服务体系
非微服务体系下
调用非微服务体系下的api,采用的是baseUrl参数,显示的声明域名。
@Component
@RetrofitClient(baseUrl = "http://a.b.c/user")
public interface RemoteUserService {
/**
* 获取用户信息
* @param memberId
* @return
*/
@POST("personHomePage/getPersonFollowData")
Result<List<Long>> getUserInfo(@Query("memberId") Long memberId);
}
微服务体系下
调用微服务体系下的api,采用的是serviceId参数,自动发现注册在nacos中的所有服务,并进行自动选择,最终实现负载均衡策略
@Component
@RetrofitClient(serviceId = "order")
public interface RemoteOrderService {
@GET("v1/order/{memberId}")
R<List<Long>> getOrderByUserId(@Path("memberId") Long memberId);
}
如何实现两种形式调用
- 发起一个请求调用的时候,retrofit实现了拦截器的功能,根据传入的参数实现了不同策略的调用
- 在自动化配置中注册到Spring Bean中的serviceInstanceChooser 实现了负载均衡的选择
public class ServiceChooseInterceptor implements Interceptor {
protected final ServiceInstanceChooser serviceInstanceChooser;
public ServiceChooseInterceptor(ServiceInstanceChooser serviceDiscovery) {
this.serviceInstanceChooser = serviceDiscovery;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Method method = Objects.requireNonNull(request.tag(Invocation.class)).method();
Class<?> declaringClass = method.getDeclaringClass();
RetrofitClient retrofitClient =
AnnotatedElementUtils.findMergedAnnotation(declaringClass, RetrofitClient.class);
String baseUrl = retrofitClient.baseUrl();
if (StringUtils.hasText(baseUrl)) {
return chain.proceed(request);
}
// serviceId服务发现
String serviceId = retrofitClient.serviceId();
URI uri = serviceInstanceChooser.choose(serviceId);
HttpUrl url = request.url();
HttpUrl newUrl = url.newBuilder()
.scheme(uri.getScheme())
.host(uri.getHost())
.port(uri.getPort())
.build();
Request newReq = request.newBuilder()
.url(newUrl)
.build();
return chain.proceed(newReq);
}
}