code.zip
一、思路
1.1、代码组件-ServerListUpdater
功能:获取到所有的服务列表
1.2、代码组件-ILoadBalancer
功能:提供客户端的负载均衡功能

1.3、组件-IRule
功能:提供具体的负载均衡策略
二、具体实现
2.1、ServerListUpdater 服务列表更新
默认实现: DefaultServerListUpdater
/*** <p> 默认服务列表更新 </p>** @Author 彳失口亍*/public class DefaultServerListUpdater extends Thread implements ServerListUpdater {public DefaultServerListUpdater(ILoadBalancer loadBalancer) {this.loadBalancer = loadBalancer;}/** 负载均衡对象 **/private ILoadBalancer loadBalancer;/** 最后更新时间 **/private volatile String lastUpdate;/** 服务列表集合 **/private static List<Server> serverList = new ArrayList<>();@Overridepublic void start(UpdateAction updateAction) {updateAction.doUpdate();lastUpdate = System.currentTimeMillis() + "";}@Overridepublic void run() {while(true){this.start(()->{// update actionsynchronized (this){// 模拟从其他平台拉取到的服务数据List<Server> serversOnRepository = Arrays.asList(new Server("ribbon-server", "127.0.0.1", "9530"));// 更新服务列表 (增量更新-剔除 host 和 port 相同的新增数据)List<Server> addServers = new ArrayList<>();serversOnRepository.forEach(item ->{if(!serverList.contains(item)){addServers.add(item);}});if(!CollectionUtils.isEmpty(addServers)){serverList.addAll(addServers);loadBalancer.addServers(addServers);}}});try {TimeUnit.SECONDS.sleep(20);} catch (InterruptedException e) {break;}}}@Overridepublic String getLastUpdate() {return lastUpdate;}}
主要方法逻辑在 run 方法中,定时从某个地址获取服务列表(这里空实现),然后将新增的服务信息保存起来。
2.2、ILoadBalancer 负载均衡功能实现类
默认实现:DefaultLoadBalancer
/*** <p> 默认的负载均衡器 </p>** @Author 彳失口亍*/public class DefaultLoadBalancer implements ILoadBalancer{public DefaultLoadBalancer(IRule rule) {this.rule = rule;}/** 服务列表集合 key:serverName,value Server.class **/private static List<Server> serverList = new ArrayList<>();/** 服务获取算法 **/private IRule rule;@Overridepublic void addServers(List<Server> newServers) {serverList.addAll(newServers);}@Overridepublic Server chooseServer(Object key) {if(null == key){throw new RuntimeException("not found the server " + key);}// 获取到指定服务名称的服务列表List<Server> servers = serverList.stream().filter(filter -> filter.getServerName().equals(key)).collect(Collectors.toList());if(StringUtils.isEmpty(servers)){throw new RuntimeException("not found the server " + key);}return rule.choose(servers);}@Overridepublic List<Server> getAllServers() {return Collections.unmodifiableList(serverList);}}
DefaultLoadBalancer 维护了 服务列表 serverList 该服务列表是由 ServerListUpdater 更新后同步过来的。
具体的负载均衡策略委派给了 IRule 来完成。
2.3、IRule 负载均衡策略实现
默认实现:RandomRule
/*** <p> 随机算法 </p>** @Author 彳失口亍*/public class RandomRule implements IRule{@Overridepublic Server choose(List<Server> servers) {int serverIndex = new Random().nextInt(servers.size());return servers.get(serverIndex);}}
2.4、RestTemplate 请求过滤器
默认实现:LoadBalanceClientHttpRequestInterceptor
/*** <p> 负载均衡过滤器 RestTemplate 过滤器</p>** @Author 彳失口亍*/public class LoadBalanceClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {public LoadBalanceClientHttpRequestInterceptor(ILoadBalancer loadBalancer) {this.loadBalancer = loadBalancer;}private ILoadBalancer loadBalancer;@Overridepublic ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {LoadBalanceHttpRequest loadBalanceHttpRequest = new LoadBalanceHttpRequest(request, loadBalancer);ClientHttpResponse originalResponse = execution.execute(loadBalanceHttpRequest, body);return originalResponse;}/** 请求包装类 **/public static class LoadBalanceHttpRequest extends HttpRequestWrapper{private ILoadBalancer loadBalancer;public LoadBalanceHttpRequest(HttpRequest request,ILoadBalancer loadBalancer) {super(request);this.loadBalancer = loadBalancer;}@Overridepublic URI getURI() {URI originUri = super.getURI();URI newUri = null;// 如果能从服务列表中获取到服务信息,则进行 url 的重新拼接Server server = loadBalancer.chooseServer(originUri.getHost());if(null != server){StringBuffer sb = new StringBuffer();sb.append(server.getHost()).append(":").append(Optional.ofNullable(server.getPort()).orElse("80"));String newHost = sb.toString();try{String url = originUri.toURL().toString();String newUrl = url.replaceFirst(originUri.getHost(), newHost);newUri = new URI(newUrl);}catch (URISyntaxException e){} catch (MalformedURLException e) {e.printStackTrace();}return newUri;}return super.getURI();}}}
三、测试
3.1、测试代码1
自己手动拼接 url
/*** <p> 客户端 API 测试 </p>** @Author 彳失口亍*/@RestControllerpublic class ClientApi {@Autowiredprivate ILoadBalancer loadBalancer;@RequestMapping("/ribbon-client/demo")public String demo(){Server server = loadBalancer.chooseServer("ribbon-server");StringBuffer sb = new StringBuffer();sb.append("http://").append(server.getHost()).append(":").append(server.getPort()).append("/ribbon-server/api");// url = http://127.0.0.1:9530/ribbon-server/apiRestTemplate restTemplate = new RestTemplate();ResponseEntity<String> entity = restTemplate.getForEntity(sb.toString(), String.class);String result = entity.getBody();return result;}}
3.2、测试代码2
让 RestTemplate 帮我们拼接
@Autowiredprivate RestTemplate restTemplate;@RequestMapping("/ribbon-client/demo2")public String demo2(){String serverName = "ribbon-server";StringBuffer sb = new StringBuffer();sb.append("http://").append(serverName).append("/ribbon-server/api");// url = http://ribbon-server/ribbon-server/apiResponseEntity<String> entity = restTemplate.getForEntity(sb.toString(), String.class);String result = entity.getBody();return result;}
四、代码逻辑图

