步骤1:先去对我们的8001和8002端口服务提供者进行改造,加上 @GetMapping(value = “/lb”)
package com.zsp.springcloud.controller;
import com.zsp.springcloud.entities.CommonResult;
import com.zsp.springcloud.entities.Payment;
import com.zsp.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@Slf4j
@RequestMapping("/payment")
public class PaymentController {
@Autowired
PaymentService paymentService;
// 显示端口名称
@Value("${server.port}")
private String serverPort;
// 服务发现Discovery 用于告诉我们注册中心有多少微服务
@Autowired
private DiscoveryClient discoveryClient;
@PostMapping(value = "/create")
public CommonResult create(@RequestBody Payment payment){
int result=paymentService.create(payment);
log.info("插入的数据是: "+payment);
if (result>0)
{
return new CommonResult(200,"插入数据成功"+serverPort,result);
}
else
{
return new CommonResult(444,"插入数据失败",null);
}
}
@GetMapping(value = "/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id){
Payment payment=paymentService.getPaymentById(id);
log.info("查询到的数据是: "+payment);
if (payment!=null)
{
return new CommonResult(200,"查询成功"+serverPort,payment);
}
else
{
return new CommonResult(444,"查询失败",null);
}
}
@GetMapping("/discovery")
public Object discovery(){
// 获取所有微服务的名称 例如 CLOUD-PAYMENT-SERVICE
List<String> services = discoveryClient.getServices();
for (String service : services) {
log.info("名称是:"+service);
}
// 给这个方法微服务名称会得到该名称下所有的微服务端口
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance : instances) {
log.info("它的id是"+instance.getServiceId()+"他的ip地址是"+instance.getHost()+"他的端口是"+instance.getPort());
}
return this.discoveryClient;
}
@GetMapping(value = "/lb")
public String getPaymentLB(){
return serverPort;
}
}
步骤2:在我们的80端口config里面注释掉原本的@LoadBalanced
package com.zsp.springcloud.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 ApplicationContextConfig {
@Bean
// @LoadBalanced //要自己写底层源码就不能使用他的注解
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
步骤3:在原本的类包下创建lb.LoadBalancer接口,定义方法,将我们集群放到定义的接口方法内。
package com.zsp.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;
import java.util.List;
public interface LoadBalancer {
//收集服务器总共有多少台能够提供服务的机器,并放到list里面
ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
步骤4:实现MyLB去实现我们写的LoadBalancer接口然后在里面重写我们的轮询算法,注意个点
这里一定要加上@Component
package com.zsp.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class MyLB implements LoadBalancer {
private AtomicInteger atomicInteger= new AtomicInteger(0);
private final int getAndIncrement(){
int current;
int next;
do{
current=atomicInteger.get();
next=current>= Integer.MAX_VALUE? 0:current+1;
}while(!atomicInteger.compareAndSet(current,next));
System.out.println("这是第"+next+"次查询");
return next;
}
@Override
public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
int index= getAndIncrement()%serviceInstances.size();
ServiceInstance instance = serviceInstances.get(index);
return instance;
}
}
步骤5:到controller里面去调用我们8001和8002端口的服务提供者最后发现可以调用到我们自定义的lb方法。
package com.zsp.springcloud.controller;
import com.zsp.springcloud.entities.CommonResult;
import com.zsp.springcloud.entities.Payment;
import com.zsp.springcloud.lb.LoadBalancer;
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.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
import java.util.List;
@RestController
@Slf4j
public class OrderController {
@Autowired
RestTemplate template;
@Autowired
LoadBalancer loadBalancer;
@Autowired
DiscoveryClient discoveryClient;
private static final String url="http://CLOUD-PAYMENT-SERVICE";
@GetMapping("/consumer/payment/create")
public CommonResult create(Payment payment){
return template.postForObject(url+"/payment/create",payment,CommonResult.class);
}
@GetMapping("/consumer/payment/get/{id}")
public CommonResult get(@PathVariable("id") Long id){
return template.getForObject(url+"/payment/get/"+id,CommonResult.class);
}
@GetMapping("/consumer/payment/getForEntity/{id}")
public CommonResult getForEntity(@PathVariable("id") Long id){
ResponseEntity<CommonResult> entity = template.getForEntity(url + "/payment/get/" + id, CommonResult.class);
if (entity.getStatusCode().is2xxSuccessful())
{
return entity.getBody();
}
else {
return new CommonResult(444,"返回错误");
}
}
@GetMapping(value = "/comsumer/payment/lb")
public String getPaymentLB(){
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
if (instances == null || instances .size() <= 0){
return null;
}
ServiceInstance serviceInstance = loadBalancer.instances(instances);
URI uri = serviceInstance.getUri();
log.info(""+uri);
return template.getForObject(uri+"/payment/lb",String.class);
}
}
有趣的是,在调用的过程中,我发现原本可以使用的方法都不能用了,这是因为同一时间内只能有一个负载均衡策略生效,当我们开启了@LoadBalanced的时候,我们自己定义的负载均衡端口就会失效,再次访问只会得到500。