springcloud实战篇五之Eureka-client(服务消费者)之Ribbon

接着之前发布的三篇,现在轮到服务消费者了,再来回顾那张经典之图

springcloud实战篇五之Eureka-client(服务消费者)之Ribbon_第1张图片

由图可以看出,服务提供者在向Eureka-Server注册服务之后,服务消费者即可以从Eureka-Server去获取服务,调用服务.因为本文汇中Eureka-Server做了集群,所以服务端调用的时候的采用Ribbon去实现负载均衡调用

首先来了解一下Ribbon

springcloud实战篇五之Eureka-client(服务消费者)之Ribbon_第2张图片

Ribbon是Netflix开源的一款用于客户端软负载均衡的工具软件。
Spring Cloud对Ribbon进行了一些封装以更好的使用Spring Boot的自动化配置理念。

Ribbon的工作 分为两步: 
1) 第一步有限选择Eureka Server,它优先选择在同一个Zone且负载较少的Server, 

2) 第二步在根据用户指定的策略,在从Server取到的服务注册列表中选择一个地址。其中Ribbon提供了多重策略,例如轮询round robin、随机Random、根据相应时间加权等。

借用这个图来演示这个Ribbon的调用过程

springcloud实战篇五之Eureka-client(服务消费者)之Ribbon_第3张图片

小结一下:Ribbon一般配合restTemplate访问restful接口

下图为Eureka-Client 服务消费者的工程目录

springcloud实战篇五之Eureka-client(服务消费者)之Ribbon_第4张图片

1.工程pom.xml文件


  4.0.0
  
    com.yxf.springcloud
    mymicroservicecloud
    0.0.1-SNAPSHOT
  
  mymicroservicecloud-consumer-dept-80
  
  
		
			com.yxf.springcloud
			mymicroservicecloud-api
			${project.version}
		
		
		
			org.springframework.cloud
			spring-cloud-starter-eureka
		
		
			org.springframework.cloud
			spring-cloud-starter-ribbon
		
		
			org.springframework.cloud
			spring-cloud-starter-config
		
		 
			org.springframework.boot
			spring-boot-starter-web
		
		
		
			org.springframework
			springloaded
		
		
			org.springframework.boot
			spring-boot-devtools
		
	
  

2.application.yml

server:
  port: 80
  
  
eureka:
  client:
    register-with-eureka: false
    service-url: 
      defaultZone: http://eureka1001.com:1001/eureka/,http://eureka1002.com:1002/eureka/,http://eureka1003.com:1003/eureka/  

3.项目启动类

package com.yxf.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

import com.yxf.myRule.MySelfRule;

@SpringBootApplication
@EnableDiscoveryClient
//在启动该微服务的时候就能去加载我们的自定义Ribbon配置类,从而使配置生效
@RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)
public class DeptConsumer80_App
{
	public static void main(String[] args)
	{
		SpringApplication.run(DeptConsumer80_App.class, args);
	}
}

4.自定义负载均衡规则:是的消费者调用的时候,每一个服务调用5次再轮询到下一个服务

package com.yxf.myRule;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.netflix.loadbalancer.IRule;

@Configuration
public class MySelfRule
{
	@Bean
	public IRule myRule()
	{
		//return new RandomRule();// Ribbon默认是轮询,我自定义为随机
		//return new RoundRobinRule();// Ribbon默认是轮询,我自定义为随机
		
		return new RandomRule_YXF();// 我自定义为每台机器5次
	}
}

package com.yxf.myRule;

import java.util.List;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

public class RandomRule_YXF extends AbstractLoadBalancerRule
{

	// total = 0 // 当total==5以后,我们指针才能往下走,
	// index = 0 // 当前对外提供服务的服务器地址,
	// total需要重新置为零,但是已经达到过一个5次,我们的index = 1
	// 
	
	
	private int total = 0; 			// 总共被调用的次数,目前要求每台被调用5次
	private int currentIndex = 0;	// 当前提供服务的机器号

	public Server choose(ILoadBalancer lb, Object key)
	{
		if (lb == null) {
			return null;
		}
		Server server = null;

		while (server == null) {
			if (Thread.interrupted()) {
				return null;
			}
			List upList = lb.getReachableServers();
			List allList = lb.getAllServers();

			int serverCount = allList.size();
			if (serverCount == 0) {
				/*
				 * No servers. End regardless of pass, because subsequent passes only get more
				 * restrictive.
				 */
				return null;
			}

//			int index = rand.nextInt(serverCount);// java.util.Random().nextInt(3);
//			server = upList.get(index);

			
//			private int total = 0; 			// 总共被调用的次数,目前要求每台被调用5次
//			private int currentIndex = 0;	// 当前提供服务的机器号
            if(total < 5)
            {
	            server = upList.get(currentIndex);
	            total++;
            }else {
	            total = 0;
	            currentIndex++;
	            if(currentIndex >= upList.size())
	            {
	              currentIndex = 0;
	            }
            }			
			
			
			if (server == null) {
				/*
				 * The only time this should happen is if the server list were somehow trimmed.
				 * This is a transient condition. Retry after yielding.
				 */
				Thread.yield();
				continue;
			}

			if (server.isAlive()) {
				return (server);
			}

			// Shouldn't actually happen.. but must be transient or a bug.
			server = null;
			Thread.yield();
		}

		return server;

	}

	@Override
	public Server choose(Object key)
	{
		return choose(getLoadBalancer(), key);
	}

	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig)
	{
		// TODO Auto-generated method stub

	}

}

5.服务提供者的controller

package com.yxf.springcloud.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.yxf.springcloud.entities.Dept;

@RestController
public class DeptController_Consumer
{

	//private static final String REST_URL_PREFIX = "http://localhost:8001";
	private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";

	/**
	 * 使用 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url, requestMap,
	 * ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。
	 */
	@Autowired
	private RestTemplate restTemplate;

	@RequestMapping(value = "/consumer/dept/add")
	public boolean add(Dept dept)
	{
		return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
	}

	@RequestMapping(value = "/consumer/dept/get/{id}")
	public Dept get(@PathVariable("id") Long id)
	{
		return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
	}

	@SuppressWarnings("unchecked")
	@RequestMapping(value = "/consumer/dept/list")
	public List list()
	{
		return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
	}

	@RequestMapping(value = "/consumer/dept/discovery")
	public Object discovery()
	{
		return restTemplate.getForObject(REST_URL_PREFIX + "/dept/discovery", Object.class);
	}

}

6.服务消费者controller

package com.yxf.springcloud.controller;

import java.util.List;

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.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.yxf.springcloud.entities.Dept;
import com.yxf.springcloud.service.DeptService;

@RestController
public class DeptController {

	@Autowired
	private DeptService service;
	@Autowired
	private DiscoveryClient client;

	@RequestMapping(value = "/dept/add", method = RequestMethod.POST)
	public boolean add(@RequestBody Dept dept)
	{
		return service.add(dept);
	}

	@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
	public Dept get(@PathVariable("id") Long id)
	{
		return service.get(id);
	}
	
	@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
	public List list()
	{
		return service.list();
	}

	
//	@Autowired
//	private DiscoveryClient client;
	@RequestMapping(value = "/dept/discovery", method = RequestMethod.GET)
	public Object discovery()
	{
		List list = client.getServices();
		System.out.println("**********" + list);

		List srvList = client.getInstances("MICROSERVICECLOUD-DEPT");
		for (ServiceInstance element : srvList) {
			System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t"
					+ element.getUri());
		}
		return this.client;
	}
}


最后演示结果(根据三个服务提供者是操作不同的数据库,出来的数据不一样区分)

springcloud实战篇五之Eureka-client(服务消费者)之Ribbon_第5张图片

刷新五次之后

springcloud实战篇五之Eureka-client(服务消费者)之Ribbon_第6张图片

再五次

springcloud实战篇五之Eureka-client(服务消费者)之Ribbon_第7张图片

你可能感兴趣的:(springcloud实战篇,yangxf专栏,springcloud实战篇,spring,java,Ribbon)