本文主要是介绍OpenFeign、RestTemplate支持自定义服务地址列表,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
- 一、背景
- 二、解决思路
- 三、定义通用配置
- 四、定义通用StaticServiceInstanceListSuppler
- 五、为指定serviceId定义专属的配置类
- 六、通过@LoadBalancerClient为指定serviceId设置配置类
- 6.1 OpenFeign
- 6.2 RestTemplate
- 七、Debug调试
一、背景
最近在支援项目时,项目组需要将后端服务部署为多个实例,且没有集成服务注册中心、反向代理、K8S等,如此提出需要客户端OpenFeign、RestTemplate等支持手动配置服务端地址列表,并支持在服务端实例间负载均衡,经过调研后给出如下基于Spring Cloud LoadBalancer的集成方案。
二、解决思路
OpenFeign、RestTemplate均是通过url对服务发起调用,具体url的负载均衡则是由Spring Cloud LoadBalancer负责,所以需要在LoadBalancer上做文章,查询相关文档后给出如下思路:
- 通过
@LoadBalancerClient(name, configuration)
注解为不同服务标识指定相应的配置类- 服务标识 对应
@FeignClient.name
,或 RestTemplate调用urlhttp://serviceId/path
中的serviceId
- 服务标识 对应
- 然后在相应的配置类中注册自定义的
ServiceInstanceListSupplier
- 最后在自定义的
ServiceInstanceListSupplier
中返回该服务标识手动配置的服务端地址列表
接下来给出核心实现代码。
三、定义通用配置
首先,自定义配置属性如下:
import org.springframework.boot.context.properties.ConfigurationProperties;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 负载均衡静态配置** @author luohq* @date 2024-04-25 9:35*/
@ConfigurationProperties(prefix = LoadBalancerStaticProps.PREFIX)
public class LoadBalancerStaticProps {public static final String PREFIX = "spring.cloud.loadbalancer.clients";/*** 客户端ServiceId到静态地址列表的映射*/private Map<String, List<String>> staticUris = new HashMap<>();public Map<String, List<String>> getStaticUris() {return staticUris;}public void setStaticUris(Map<String, List<String>> staticUris) {this.staticUris = staticUris;}@Overridepublic String toString() {return "LoadBalancerStaticProps{" +"staticUris=" + staticUris +'}';}
}
后续可通过如下示例配置,手动指定不同服务标识对应的服务端地址列表:
spring:cloud:loadbalancer:clients:# 配置负载均衡静态地址static-uris:# app-rbac服务的静态地址列表app-rbac:- http://localhost:8081- http://localhost:8082# app-atom服务的静态地址列表app-atom:- http://localhost:9081- http://localhost:9082
四、定义通用StaticServiceInstanceListSuppler
StaticServiceInstanceListSuppler实现了ServiceInstanceListSupplier接口,
这个接口是Spring Cloud LoadBalancer的一部分,是一个通用的客户端负载均衡器。
StaticServiceInstanceListSuppler支持自定义serviceId对应的服务地址列表serviceStaticUriList,
同时提供create方法,支持从前文定义的配置属性LoadBalancerStaticProps 中(即从配置文件中)获取serviceId对应的服务地址列表。
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.util.Assert;
import reactor.core.publisher.Flux;import java.net.URI;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;/*** 静态服务地址提供器** @author luohq* @date 2024-04-25*/
public class StaticServiceInstanceListSuppler implements ServiceInstanceListSupplier {/*** 服务标识*/private final String serviceId;/*** 服务地址列表*/private final List<String> serviceStaticUriList;public StaticServiceInstanceListSuppler(String serviceId, List<String> serviceStaticUriList) {Assert.notNull(serviceId, "serviceId may not be null");Assert.notEmpty(serviceStaticUriList, "serviceStaticUriList may not be null");this.serviceId = serviceId;this.serviceStaticUriList = serviceStaticUriList;}@Overridepublic String getServiceId() {return serviceId;}@Overridepublic Flux<List<ServiceInstance>> get() {List<ServiceInstance> defaultServiceInstanceList = IntStream.range(0, serviceStaticUriList.size()).mapToObj(i -> {DefaultServiceInstance defaultServiceInstance = new DefaultServiceInstance();defaultServiceInstance.setServiceId(this.serviceId);defaultServiceInstance.setInstanceId(this.serviceId + i);defaultServiceInstance.setUri(URI.create(serviceStaticUriList.get(i)));return defaultServiceInstance;}).collect(Collectors.toList());return Flux.just(defaultServiceInstanceList);}public static StaticServiceInstanceListSuppler create(String serviceId, LoadBalancerStaticProps loadBalancerStaticProps) {return new StaticServiceInstanceListSuppler(serviceId, loadBalancerStaticProps.getStaticUris().get(serviceId));}
}
五、为指定serviceId定义专属的配置类
如下实现即对应serviceId=app-rbac
服务的专属配置类,
不同的serviceId可再单独定义相应的配置类。
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
/*** RBAC客户端负载均衡静态配置** @author luohq* @date 2024-04-25 9:35*/
public class RbacClientLoadBalancerStaticConfiguration {public static final String SERVICE_ID = "app-rbac";@Bean@Primarypublic ServiceInstanceListSupplier serviceInstanceListSupplier(LoadBalancerStaticProps loadBalancerStaticProps) {return StaticServiceInstanceListSuppler.create(SERVICE_ID, loadBalancerStaticProps);}
}
六、通过@LoadBalancerClient为指定serviceId设置配置类
6.1 OpenFeign
如果项目中使用的是OpenFeign,以下配置已足够:
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.context.annotation.Configuration;/*** RBAC客户端负载均衡静态配置** @author luohq* @date 2024-04-25 9:35*/
@Configuration
@LoadBalancerClients({//自定义RBAC服务配置@LoadBalancerClient(name = RbacClientLoadBalancerStaticConfiguration.SERVICE_ID,configuration = RbacClientLoadBalancerStaticConfiguration.class)
})
@EnableConfigurationProperties({LoadBalancerStaticProps.class})
public class LoadBalancerStaticConfiguration2 {}
6.2 RestTemplate
如果项目中使用的是RestTemplate,那么还需要通过@LoadBalanced注解设置RestTemplate支持负载均衡,
具体配置代码如下:
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;/*** RBAC客户端负载均衡静态配置** @author luohq* @date 2024-04-25 9:35*/
@Configuration
@LoadBalancerClients({//自定义RBAC服务配置@LoadBalancerClient(name = RbacClientLoadBalancerStaticConfiguration.SERVICE_ID,configuration = RbacClientLoadBalancerStaticConfiguration.class)
})
@EnableConfigurationProperties({LoadBalancerStaticProps.class})
public class LoadBalancerStaticConfiguration2 {/*** 通过@LoadBalanced注解开启RestTemplate负载均衡能力*/@LoadBalanced@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}
七、Debug调试
Spring Cloud LoadBalancer默认使用的是RoundRobinLoadBalancer,可重点关注RoundRobinLoadBalancer中获取服务实例的代码。
参考:
https://spring.io/guides/gs/spring-cloud-loadbalancer
https://juejin.cn/post/7266315019294490661
https://docs.spring.io/spring-cloud-commons/docs/3.1.8/reference/html/#spring-cloud-loadbalancer
这篇关于OpenFeign、RestTemplate支持自定义服务地址列表的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!