不懂Ribbon原理的可以进来看看哦,分析SpringBoot自动装配完成了Ribbon哪些核心操作
前面详细的给大家介绍了SpringBoot的核心内容,有了这部分的基础支持的话,我们再来分析SpringCloud中的相关组件就很容器了,本文我们来给大家开始介绍Ribbon的相关内容,首先来介绍下Ribbon项目在启动的时候完成了哪些操作。
一、项目案例准备
首先我们大家案例环境,通过【RestTemplate】来实现服务调用,通过【Ribbon】实现客户端负载均衡操作。

1.Order服务
我们的Order服务作为服务提供者。创建SpringBoot项目,并添加相关依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.9</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bobo.springcloud</groupId>
<artifactId>spring-cloud-order-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-order-server</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR10</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
然后在属性文件中添加相关的配置
spring.application.name=spring-cloud-order-service
server.port=8081
然后创建自定义的Controller 提供对外的服务
@RestController
public class OrderController {
@Value("${server.port}")
private int port;
@GetMapping("/orders")
public String orders(){
System.out.println("Order 服务端口是:"+port);
return "Order Services ..... ";
}
}
然后我们可以分别启动两个Order服务,端口分别设置为 8081和8082
2.User服务
User服务作为调用用Order服务的客户端。也是我们要重点介绍【Ribbon】的服务。同样创建一个SpringBoot项目,添加相关的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bobo.springcloud</groupId>
<artifactId>spring-cloud-user-service2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-user-service2</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR10</spring-cloud.version>
</properties>
<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-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
然后在属性文件中配置相关信息
spring.application.name=spring-cloud-user-service
spring-cloud-order-service.ribbon.listOfServers=localhost:8081,localhost:8082
然后创建自定义的Controller来实现服务的调用
@RestController
public class UserController {
@Autowired
public RestTemplate restTemplate;
@Autowired
LoadBalancerClient loadBalancerClient;
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
@GetMapping("/users")
public String users(){
ServiceInstance choose = loadBalancerClient.choose("spring-cloud-order-service");
String url = String.format("http://%s:%s",choose.getHost(),choose.getPort()+"/orders");
//return restTemplate.getForObject(url,String.class);
return restTemplate.getForObject("http://spring-cloud-order-service/orders",String.class);
}
}
然后启动User服务访问,可以看到【Ribbon】默认通过轮询的方式来实现了服务的调用

二、Ribbon原理分析
应用比较简单,我们主要是来分析下【Ribbon】的核心原理,先来看看自动装配做了哪些事情。
1.RibbonAutoConfiguration
Ribbon在系统启动的时候自动装配完成的设置,我们先来看看对应的spring.factories 中的配置信息吧

emsp; 所以我们要继续来看【RibbonAutoConfiguration】配置类,我们贴出【RibbonAutoConfiguration】的关键信息
@Configuration
@Conditional({RibbonAutoConfiguration.RibbonClassesConditions.class})
@RibbonClients
@AutoConfigureAfter(
name = {"org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration"}
)
// RibbonAutoConfiguration配置类注入容器后会完成 LoadBalancerAutoConfiguration 和 AsyncLoadBalancerAutoConfiguration 的注入
@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})
public class RibbonAutoConfiguration {
/**
* 如果IoC容器中不存在 LoadBalancerClient 类型的对象就注入一个
* 具体注入的类型为 RibbonLoadBalancerClient 对象
**/
@Bean
@ConditionalOnMissingBean({LoadBalancerClient.class})
public LoadBalancerClient loadBalancerClient() {
return new RibbonLoadBalancerClient(this.springClientFactory());
}
// 省略其他代码
通过源码查看我们知道在SpringBoot项目启动的时候完成了【LoadBalancerClient】对象的注入,且具体的类型为【RibbonLoadBalancerClient】,同时还会完成【LoadBalancerAutoConfiguration】这个配置类型的加载。在看【LoadBalancerAutoConfiguration】做了什么事情之前,我们先来搞清楚【@LoadBalanced】注解的作用
2.LoadBalancerAutoConfiguration
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
【@LoadBalanced】本质上就是一个【@Qualifier】注解。作用就是标记,我们通过案例来演示说明。
定义一个简单的【User】类
public class User {
String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
然后定义一个Java配置类,有两个添加了【@LoadBalanced】注解,有一个没有加。
@Configuration
public class JavaConfig {
@LoadBalanced
@Bean("user1")
public User user1(){
return new User("user1");
}
@Bean("user2")
public User user2(){
return new User("user2");
}
@LoadBalanced
@Bean("user3")
public User user3(){
return new User("user3");
}
}
然后创建我们的控制器,来测试使用
@RestController
public class UsersController {
@LoadBalanced
@Autowired
List<User> list = Collections.emptyList();
@GetMapping("/querys")
public String query(){
return list.toString();
}
}
项目结构

启动SpringBoot项目后我们看效果

搞清楚了【@LoadBalanced】的作用后,我们再来看看【LoadBalancerAutoConfiguration】的配置加载做了什么事情
public class LoadBalancerAutoConfiguration {
/**
* 1.
* 获取IoC容器中所有的被【@LoadBalanced】注解修饰的RestTemplate对象
* 这些对象保存在了一个集合中
**/
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
/**
* 4.
* 向容器中注入了 SmartInitializingSingleton 对象,并且实现了 SmartInitializingSingleton 接口中声明的
* afterSingletonsInstantiated 方法,在该方法中 通过3 中的 RestTemplateCustomizer中定义的 customize 方法
* 实现了 RestTemplate 对象拦截器的植入
**/
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(
LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
/**
* 2.
* 创建了一个 LoadBalancerInterceptor 并注入到了容器中
**/
@Bean
public LoadBalancerInterceptor loadBalancerInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
/**
* 3.
* 创建了一个 RestTemplateCustomizer 并注入到了容器中
* 而且通过内部类的方式定义定义了 RestTemplateCustomizer 接口中的 customize 方法的逻辑
**/
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
// 获取 RestTemplate 中原有的 拦截器
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
// 在原有的拦截器的基础上 添加了一个 LoadBalancerInterceptor
list.add(loadBalancerInterceptor);
// 然后将添加有新的 拦截器的集合 设置到了 RestTemplate 对象中
restTemplate.setInterceptors(list);
};
}
}
// 省略其他代码
}
通过对应的备注大家可以搞清楚该配置类的作用是实现了对【RestTemplate】对象(被@LoadBalanced修饰)植入
【LoadBalancerInterceptor】拦截器的功能。
小结Ribbon系统时的操作

~好了相信大家应该对于在自动装配时完成了 【RestTemplate】植入拦截器的逻辑应该很清楚了,下篇文章我们详细介绍Ribbon具体是怎么来处理负载均衡逻辑的,敬请期待,欢迎一键三连哦!!!
不懂Ribbon原理的可以进来看看哦,分析SpringBoot自动装配完成了Ribbon哪些核心操作的更多相关文章
- 不懂Ribbon原理的可以进来看看哦,分析RibbonClientConfiguration完成了哪些核心初始操作
本文在前一篇文章的基础上来继续分析Ribbon的核心内容. 不懂Ribbon原理的可以进来看看哦,分析SpringBoot自动装配完成了Ribbon哪些核心操作 RibbonClientConfi ...
- SpringBoot启动流程分析(五):SpringBoot自动装配原理实现
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot自动装配原理解析
本文包含:SpringBoot的自动配置原理及如何自定义SpringBootStar等 我们知道,在使用SpringBoot的时候,我们只需要如下方式即可直接启动一个Web程序: @SpringBoo ...
- springboot自动装配原理
最近开始学习spring源码,看各种文章的时候看到了springboot自动装配实现原理.用自己的话简单概括下. 首先打开一个基本的springboot项目,点进去@SpringBootApplica ...
- 小BUG大原理 | 第一篇:重写WebMvcConfigurationSupport后SpringBoot自动配置失效
一.背景 公司的项目前段时间发版上线后,测试反馈用户的批量删除功能报错.正常情况下看起来应该是个小BUG,可怪就怪在上个版本正常,且此次发版未涉及用户功能的改动.因为这个看似小BUG我了解到不少未知的 ...
- springboot自动装配原理,写一个自己的start
springboot自动装配原理 第一次使用springboot的时候,都感觉很神奇.只要加入一个maven的依赖,写几行配置,就能注入redisTemple,rabbitmqTemple等对象. 这 ...
- SpringBoot | 2.1 SpringBoot自动装配原理
@ 目录 前言 1. 引入配置文件与配置绑定 @ImportResource @ConfigurationProperties 1.1 @ConfigurationProperties + @Enab ...
- SpringBoot 自动装配原理
早期的Spring项目需要添加需要配置繁琐的xml,比如MVC.事务.数据库连接等繁琐的配置.Spring Boot的出现就无需这些繁琐的配置,因为Spring Boot基于约定大于配置的理念,在项目 ...
- springboot自动装配原理回顾、配置文件分析
配置文件 spring boot官方文档 官方外部配置文件说明参考文档 自动配置原理分析 1. SpringBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfigurat ...
随机推荐
- 尝试用面向对象思维理解Vue组件
什么是组件 用面向对象的思维去理解Vue组件,可以将所有的事物都抽象为对象,而类或者说是组件,都具有属性和操作. 如抽取人类为组件,其基本的属性有姓名.年龄.国籍:基本的方法有吃饭.睡觉.跑步等. & ...
- CRM系统什么时候需要使用
CRM客户关系管理系统,相信每个人都会有所了解.现如今随着企业的发展需求,CRM软件已经成为了企业管理的刚需.无论是何种行业和规模的企业,客户都是最重要的资源,提高客户满意度也是企业的首要任务.如果您 ...
- Python小白的数学建模课-B5. 新冠疫情 SEIR模型
传染病的数学模型是数学建模中的典型问题,常见的传染病模型有 SI.SIR.SIRS.SEIR 模型. 考虑存在易感者.暴露者.患病者和康复者四类人群,适用于具有潜伏期.治愈后获得终身免疫的传染病. 本 ...
- consul 多节点/单节点集群搭建
三节点配置 下载安装包 mkdir /data/consul mkdir /data/consul/data curl -SLO https://github.com/consul/1.9.5/con ...
- 获取 Windows 密码「GitHub 热点速览 v.21.28」
作者:HelloGitHub-小鱼干 安全问题一直是 GitHub 的一大热点,因为数据安全问题诞生的各类自托管服务便是.而本周周榜上的 2 个和安全主题相关的项目,有些不同.mimikatz 是个老 ...
- Java:Apache Commons 工具类介绍及简单使用
Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动.下面是我这几年做开发过程中自己用过的工具类做简单介绍. Commons简介 组件 功能介绍 commo ...
- kali安装angr
最近打算重新学习一波angr,先把环境搭好 1. 先安装virtualenv,这玩意是可以创建一个纯净的python环境,我陷入了沉思,pyenv好像也可以 这里利用豆瓣的源下载,非常快而且很舒服 p ...
- 使用 Cron4j 表达式 在 Solon 里开发定时任务
cron4j 是一个轻量级的Java任务调度工具.cron4j-solon-plugin 是 solon 对 cron4j 的适配插件 添加 maven 引用 <dependency> & ...
- 续PA协商过程
续PA协商过程 当sw3的接口恢复之后会发生2中情况. ①sw3的G0/0/2口先发BPDU ②sw3的G0/0/3口先发BPDU sw3先发送BPDU sw3和sw1的交互过程: sw3的2口恢复后 ...
- mysql中函数cast使用
CAST函数语法规则是:Cast(字段名 as 转换的类型 ),其中类型可以为: CHAR[(N)] 字符型DATE 日期型DATETIME 日期和时间型DECIMAL float型SIGNED in ...