原理
利用 springcloud提供的 DiscoveryClient 服务发现功能,获取注册在注册中心的服务列表,然后根据一定算法从该列表中选择一个作为本次调用服务的服务提供者。
开发前准备
微服务项目,需要有注册中心,有服务提供者和服务消费者 本例使用 eureka 作为注册中心,两个提供者,一个消费者

http客户端
使用 RestTemplate 作为远程调用的client 注意不要使用 @LoadBalanced 这个负载均衡的注解
package com.li.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
策略接口
public interface MyLoadBalance {
ServiceInstance getIntacnce(List<ServiceInstance> serviceInstances);
}
package com.li.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Random;
@Component
@Slf4j
public class MyLoadBalanceImpl implements MyLoadBalance {
@Override
public ServiceInstance getIntacnce(List<ServiceInstance> serviceInstances) {
Random random = new Random();
int index = random.nextInt(serviceInstances.size());
log.info("获得的微服务的对应下标为:{}",index);
return serviceInstances.get(index);
}
}
使用自定义负载均衡-随机策略
package com.li.controller;
import com.li.config.MyLoadBalance;
import com.li.entities.Provider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
@Slf4j
@RestController
public class MyLoadBalanceController {
@Autowired
private MyLoadBalance myLoadBalance;
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private RestTemplate restTemplate;
@PostMapping("/myloadbalance")
public String test(@RequestBody Provider provider){
List<ServiceInstance> instances = discoveryClient.getInstances("PROVIDER-SERVICE");
if (instances==null||instances.size()==0)
return "无可用服务";
ServiceInstance intacnce = myLoadBalance.getIntacnce(instances);
URI uri = intacnce.getUri();
log.info("获得的url:{}",uri);
return restTemplate.postForObject(uri+"/provider", provider, String.class);
}
}
每次调用都重新获取服务列表实例,是为了防止 有的实例出现故障后,还存在列表中。
测试
 被调用的实例下标为 0 和1,且是不规则出现的,说明 随机策略实现成功。 如果要写其他策略,原理都大同小异。
自定义轮询策略
package com.li.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
@Component
@Slf4j
public class MyLoadBalanceImpl implements MyLoadBalance {
private final AtomicInteger atomicInteger= new AtomicInteger(0);
@Override
public ServiceInstance getRobin(List<ServiceInstance> serviceInstances){
int last;
int current;
do {
last=atomicInteger.get();
current=last>Integer.MAX_VALUE ? 0 : last+1;
}while (!this.atomicInteger.compareAndSet(last, current));
log.info("已经调用了{} 次, 本次调用的下标为 {}",last,current% serviceInstances.size());
return serviceInstances.get(current % serviceInstances.size());
}
}
@PostMapping("/myloadbalance2")
public String testRobin(@RequestBody Provider provider){
List<ServiceInstance> instances = discoveryClient.getInstances("PROVIDER-SERVICE");
if (instances==null||instances.size()==0)
return "无可用服务";
ServiceInstance intacnce = myLoadBalance.getRobin(instances);
URI uri = intacnce.getUri();
log.info("获得的url:{}",uri);
return restTemplate.postForObject(uri+"/provider", provider, String.class);
}
测试  轮询策略完成
|