多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
除了选用Ribbon官方提供的均衡策略外,我们也可以自定义均衡策略。 <br/> 在消费端 cloud-comsumer-order80 自定义均衡策略的步骤如下: **1. 自定义我们的均衡策略** (1)需求:Ribbon默认的轮询策略是每台机器一次,然后轮到下一个机器。现在要求在轮询策略的基础上加上新的需求,即每个服务器要求被调用5次才开始轮到下一个服务器。 (2)下面先让我们来看一下 RandomRule 均衡策略的源码,了解它的基本原理。 *`com.netflix.loadbalancer.RandomRule`* ```java package com.netflix.loadbalancer; import com.netflix.client.config.IClientConfig; import edu.umd.cs.findbugs.annotations.SuppressWarnings; import java.util.List; import java.util.Random; public class RandomRule extends AbstractLoadBalancerRule { Random rand = new Random(); public RandomRule() { } /** * 其实实现其主要作用的就是该方法 */ @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"}) public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { return null; } else { Server server = null; while(server == null) { if (Thread.interrupted()) { return null; } // 1. 获取所有可用的服务 List<Server> upList = lb.getReachableServers(); // 2. 获取所有的服务,可用的和不可用的 List<Server> allList = lb.getAllServers(); int serverCount = allList.size(); if (serverCount == 0) { return null; } // 3. 可以看到随机就是随机地在一个可用的服务列表中随机的返回一个Server int index = this.rand.nextInt(serverCount); server = (Server)upList.get(index); if (server == null) { Thread.yield(); } else { if (server.isAlive()) { return server; } server = null; Thread.yield(); } } return server; } } /** * 该方法返回最终选择的均衡器 */ public Server choose(Object key) { return this.choose(this.getLoadBalancer(), key); } public void initWithNiwsConfig(IClientConfig clientConfig) { } } ``` (3)根据上面的需求实现的自定义均衡器如下。 ```java public class MyRoundRibbonByFiveRule extends AbstractLoadBalancerRule { /** * 每台总共被调用的次数,目前要求每台被调用5次 */ private int total = 0; /** * 当前提供服务的机器号 */ 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; } // (1)获取所有可用的机器和所有机器(包括可用的和不可用的) List<Server> upList = lb.getReachableServers(); List<Server> allList = lb.getAllServers(); int serverCount = allList.size(); if (serverCount == 0) { return null; } // (2)根据需求设计的均衡器选择规则如下 // int index = rand.nextInt(serverCount); // server = upList.get(index); if (total < 5) { server = upList.get(currentIndex); total++; } else { total = 0; currentIndex++; if (currentIndex >= upList.size()) { currentIndex = 0; } } if (server == null) { Thread.yield(); continue; } if (server.isAlive()) { return (server); } 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 } } ``` **2. 将自定义的均衡器进行装配** 有一个要求:<mark>就是装配自定义均衡器的类不能在`@ComponentScan`的包及其子包下</mark>,如下的启动类。 ```java // 1. @SpringBootApplication标注的类为启动类 @SpringBootApplication public class OrderMain80 { public static void main(String[] args) { SpringApplication.run(OrderMain80.class, args); } } // 2. @SpringBootApplication用到了@ComponentScan @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication { // 3. 所以就是装配自定义均衡器的类不能与启动类同级目录,或者子目录。 ``` 说了这么多,下面就将自定义的均衡器进行装配。 ```java /** * 注意:我当前模块的启动类位置在 com.atguigu.springcloud.OrderMain80 * 所以当前装配的自定义均衡策略的类不能定义在com.atguigu.springcloud包下及其子包下 */ @Configuration public class MyRoundRibbonByFiveRuleConfig { /** * 将自定义的均衡器进行装配。 */ @Bean public IRule myRoundRibbonByFiveRule() { return new MyRoundRibbonByFiveRule(); } } ``` **3. 在消费端启动类上添加注解`@RibbonClient`** ```java @SpringBootApplication @EnableEurekaClient /** * name:服务端的 spring.application.name 配置 * configuration:我们自定义的均衡策略 */ @RibbonClient(name = "${provider.payment.name}",configuration = MyRoundRibbonByFiveRuleConfig.class) public class OrderMain80 { public static void main(String[] args) { SpringApplication.run(OrderMain80.class,args); } } ``` **4. 测试效果** 访问消费端的 http://localhost/order/idport ,经过测试,确实刷新5次后才会更换下一个服务器。