SpringCloud
为开发者提供了在分布式系统中的一些常用的组件(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线,一次性令牌,全局锁定,决策竞选,分布式会话集群状态)。使用Spring Cloud开发人员可以快速地完成实现这些模式的服务和应用程序。它们在任何分布式环境中都能很好地工作
Ribbon
是 Netflix
开源的基于 HTTP
和 TCP
的客户端负载均衡器框架,目前也已被 SpringCloud
团队集成在 spring-cloud-netflix
子项目下,主要用于客户端软负载功能,内部已实现了 随机
、 轮询
、 权重
、 减压(选取压力最小的)
等常见的负载算法,同时也提供了 ILoadBalance
与 IRule
两个接口方便我们自己编写适合自己的负载算法
交互图
要尝试 SpringCloudRibbon
首要的就是准备一个服务注册中心,还不太清楚的可以在回头看看上一章 认识Eureka
,这里就不做过多赘述了,准备 eureka-server(回顾上一章)
、 product-server
、 order-server
三个项目,后面的两个可以理解为上一章的 eureka-client
详情参考上一章,或从文末的 GITHUB 链接获取对应篇幅的完整代码
一个普通的 EurekaClient
即可,详情参考上一章,或从文末的 GITHUB 链接获取对应篇幅的完整代码
一个普通的 EurekaClient
依赖
细心的小伙伴会发现,这和一个普通的 EurekaClient
也没啥区别啊,没任何额外依赖的,那是因为在 spring-cloud-starter-netflix-eureka-client
中已经帮我们依赖过 spring-cloud-starter-netflix-ribbon
了。假如使用 consul
、 zookeeper
、 etcd
等容器为服务发现为者时,就必须依赖 spring-cloud-starter-netflix-ribbon
包
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
配置文件
在 src/main/resources
目录下创建一个 bootstrap.yml
的文件,写上 eureka 相关配置信息
server:
port: 7072
spring:
application:
name: order-server
eureka:
instance:
prefer-ip-address: true
instance-id: ${spring.cloud.client.ip-address}:${spring.application.instance_id:${server.port}}
client:
service-url:
defaultZone: http://localhost:7071/eureka/
主函数
各位小伙伴对 SpringBoot
中的 RestTemplate
应该都不陌生,它是由 SpringBoot
提供而不是 SpringCloud
,无负载功能,为了方便开发者, SpringCloud
团队提供了一个 @LoadBalanced
注解(默认采用轮训算法)
package com.battcn;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
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;
/**
* @author Levin
*/
@EnableDiscoveryClient
@SpringBootApplication
public class OrderApplication {
@Configuration
class MyConfiguration {
@LoadBalanced
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
控制器
客户端( order-server:7702
)从 EurekaServer
同步了 product-server:7703
和 product-server:7704
这个时候它是如何知晓注册表中的信息呢?上一章中遗留了一个知识点就是 DiscoveryClient
,通过它就可以获得注册表中客户端的信息了,下列代码块演示了 DiscoveryClient
的简单用法,更多 API 可以自行尝试
package com.battcn.controller;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* @author Levin
* @since 2018/9/28 0028
*/
@RestController
@RequestMapping("/orders")
public class OrderController {
private final RestTemplate restTemplate;
private final DiscoveryClient discoveryClient;
@Autowired
public OrderController(RestTemplate restTemplate, DiscoveryClient discoveryClient) {
this.restTemplate = restTemplate;
this.discoveryClient = discoveryClient;
}
@GetMapping
public String query() {
final List<String> services = discoveryClient.getServices();
for (String service : services) {
List<ServiceInstance> list = discoveryClient.getInstances(service);
for (ServiceInstance instance : list) {
System.out.println(instance.getUri() + "/" + service + " - " + instance.getServiceId());
}
}
return restTemplate.getForObject("http://PRODUCT-SERVER/products", String.class);
}
}
Why
有的小伙伴对上面的内容会存在一些疑问,为什么没有写 IP:PORT 了,而是写了一串字符,它是怎么做到的?
用通俗的概念来说,它就是编码与解码操作,还记得 Eureka Server UI 中 Application 吗?
编码:根据 spring.application.name 设置 serviceId
Server ID:PRODUCT-SERVER
Client A :http://localhost:7073/products
Client B :http://localhost:7074/products
解码:通过 serviceId 找到对应的客户端,
然后根据客户端配置的负载算法从对应集合中
找出符合当前算法条件的结果,最后拼接出相应的 http 地址即可
解码前:http://PRODUCT-SERVER/products
那么将 http://PRODUCT-SERVER 替换成 instance.getUri() 内容是不是就出来了
http://localhost:7073/products 和 http://localhost:7074/products
假如我们不想使用轮训了,换换口味改成随机算法,又或者想自己写一套适合自己的负载算法,可以用下面这种方式
package com.battcn.config;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Levin
* @since 2018/9/28 0028
*/
@Configuration
public class RibbonRuleConfiguration {
@Bean
public IRule ribbonRule() {
return new RandomRule();
}
}
@RibbonClient(name = "ribbonRule",configuration = RibbonRuleConfiguration.class)
public class OrderController {
}
目前很多大佬都写过关于 SpringCloud
的教程了,如有雷同,请多多包涵,本教程基于最新的 spring-cloud:Finchley.SR1
编写...
个人博客:http://blog.battcn.com/
全文代码:https://github.com/battcn/spring-cloud2-learning/tree/master/chapter2
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有