nacos2.x已不支持ribbon,使用nacos2.x需要手动引入LoadBalancer
1 手写随机负载均衡算法
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Resource private RestTemplate restTemplate;
@RequestMapping("/test") public String loadbalance(){ List<ServiceInstance> instances = discoveryClient.getInstance("order"); List<String> uris = instances.stream().map(instance -> instance.getUri().toString() + "/order/query").collect(Collections.toList()); int i = ThreadLocalRandom.current().nextInt(uris.size()); String uri = uris.get(i); System.out.printLn("访问地址为" + uri); return this.restTemplate.getForObject(uri, String.calss); }
|
2 LoadBalancerClient API
https://spring.io/guides/gs/spring-cloud-loadbalancer/
(1)引入依赖
1 2 3 4
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
|
(2)写代码
1 2 3 4 5 6 7 8 9
| @Resource private LoadBalancerClient loadBalancerClient;
@RequestMapping("/loadbalancerclient-api") public String loadbalancerclientApi(){ ServiceInstance serviceInstance = loadBalancerClient.choose("order"); String url = serviceInstance.getUri().toString()+"/order/query"; return restTemplate.getForObject(url,String.class); }
|
3 @LoadBalanced注解方式
(1)引入loadbalancer starter
1 2 3 4
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
|
(2)自定义一个@LoadBalanced注解的RestTemplate
1 2 3 4 5
| @Bean @LoadBalanced public RestTemplate restTemplateLoadBalancer(){ return new RestTemplate(); }
|
(3)写代码
1 2 3 4 5 6 7
| @Resource private RestTemplate restTemplateLoadBalancer;
@RequestMapping("/loadbalancerclient-annotation") public String loadbalancerclientAnnotation(){ return this.restTemplateLoadBalancer.getForObject("http://order/order/query", String.class); }
|
4 更改默认负载均衡方式
https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#switching-between-the-load-balancing-algorithms
默认的负载均衡为轮询
(1)定义配置类
1 2 3 4 5 6 7
| public class CustomLoadBalancerConfiguration { @Bean ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) { String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name,ServiceInstanceListSupplier.class), name); } }
|
(2)在启动类上通过@LoadBalancerClients注解使用自定义的配置类
1 2 3
| @SpringBootApplication @LoadBalancerClients(defaultConfiguration = CustomLoadBalancerConfiguration.class) public class UserApplication {
|
5 核心源码分析
实际上,loadbalancer注解就是给RestTemplate添加了一个拦截器,调用过程简单来说,就是RestTemplate加上loadbalancer注解后,在创建请求之前添加了一个拦截器,在拦截器中通过服务名称调用LoadBalancer的choose方法,获取到真实的ip:port然后再拼接上具体的接口,替换原有uri,再通过RestTemplate进行远程调用。
5.1 LoadBalancerClient#choose
(1)LoadBalancerClient的自动装配
BlockingLoadBalancerClientAutoConfiguration
1 2 3 4 5 6
| @Bean @ConditionalOnBean(LoadBalancerClientFactory.class) @ConditionalOnMissingBean public LoadBalancerClient blockingLoadBalancerClient(LoadBalancerClientFactory loadBalancerClientFactory) { return new BlockingLoadBalancerClient(loadBalancerClientFactory); }
|
(2)LoadBalancerClient-choose源码分析

5.2 @LoadBalanced和RestTemplate
5.2.1 RestTamplate调用过程

5.2.2 RestTemplate使用@LoadBalanced
(1)向Spring IoC容器中注入RestTemplate的Bean
1 2 3 4 5
| @Bean @LoadBalanced public RestTemplate restTemplateLoadBalancer(){ return new RestTemplate(); }
|
(2)依赖注入
1 2 3 4 5 6 7 8
| @Configuration @ConditionalOnClass(RestTemplate.class) @ConditionalOnBean(LoadBalancerClient.class) @EnableConfigurationProperties(LoadBalancerRetryProperties.class) public class LoadBalancerAutoConfiguration { @LoadBalanced @Autowired(required = false) private List<RestTemplate> restTemplates = Collections.emptyList();
|
(3)创建拦截器
1 2 3 4 5
| @Bean public LoadBalancerInterceptor loadBalancerInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) { return new LoadBalancerInterceptor(loadBalancerClient, requestFactory); }
|
(4)给指定的restTemplate添加拦截器属性
1 2 3 4 5 6 7 8 9
| @Bean @ConditionalOnMissingBean public RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) { return restTemplate -> { List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors()); list.add(loadBalancerInterceptor); restTemplate.setInterceptors(list); }; }
|
(5)拥有了拦截器能力的RestTemplate
