手把手带你分析SpringBoot自动装配完成了Ribbon哪些核心操作

网友投稿 220 2022-10-05


手把手带你分析SpringBoot自动装配完成了Ribbon哪些核心操作

目录一、项目案例准备1.Order服务2.User服务二、Ribbon原理分析1.RibbonAutoConfiguration2.LoadBalancerAutoConfiguration总结

一、项目案例准备

首先我们大家案例环境,通过【RestTemplate】来实现服务调用,通过【Ribbon】实现客户端负载均衡操作。

1.Order服务

我们的Order服务作为服务提供者。创建SpringBoot项目,并添加相关依赖

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

org.springframework.boot

spring-boot-starter-parent

2.4.9

com.bobo.springcloud

spring-cloud-order-server

0.0.1-SNAPSHOT

spring-cloud-order-server

Demo project for Spring Boot

1.8

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-test

test

org.springframework.cloud

spring-cloud-dependencies

Hoxton.SR10

pom

import

org.springframework.boot

spring-boot-maven-plugin

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

org.springframework.boot

spring-boot-starter-parent

2.4.9

com.bobo.springcloud

spring-cloud-order-server

0.0.1-SNAPSHOT

spring-cloud-order-server

Demo project for Spring Boot

1.8

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-test

test

org.springframework.cloud

spring-cloud-dependencies

Hoxton.SR10

pom

import

org.springframework.boot

spring-boot-maven-plugin

然后在属性文件中添加相关的配置

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项目,添加相关的依赖

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

org.springframework.boot

spring-boot-starter-parent

2.3.9.RELEASE

com.bobo.springcloud

spring-cloud-user-service2

0.0.1-SNAPSHOT

spring-cloud-user-service2

Demo project for Spring Boot

1.8

Hoxton.SR10

org.springframework.boot

spring-boot-starter-web

org.springframework.cloud

spring-cloud-starter-netflix-ribbon

org.springframework.boot

spring-boot-starter-test

test

org.springframework.cloud

spring-cloud-dependencies

${spring-cloud.version}

pom

import

mDVkrTp

org.springframework.boot

spring-boot-maven-plugin

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

org.springframework.boot

spring-boot-starter-parent

2.3.9.RELEASE

com.bobo.springcloud

spring-cloud-user-service2

0.0.1-SNAPSHOT

spring-cloud-user-service2

Demo project for Spring Boot

1.8

Hoxton.SR10

org.springframework.boot

spring-boot-starter-web

org.springframework.cloud

spring-cloud-starter-netflix-ribbon

org.springframework.boot

spring-boot-starter-test

test

org.springframework.cloud

spring-cloud-dependencies

${spring-cloud.version}

pom

import

mDVkrTp

org.springframework.boot

spring-boot-maven-plugin

然后在属性文件中配置相关信息

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 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 restTemplates = Collections.emptyList();

@Autowired(required = false)

private List transformers = Collections.emptyList();

/**

* 4.

* 向容器中注入了 SmartInitializingSingleton 对象,并且实现了 SmartInitializingSingleton 接口中声明的

* afterSingletonsInstantiated 方法,在该方法中 通过3 中的 RestTemplateCustomizer中定义的 customize 方法

* 实现了 RestTemplate 对象拦截器的植入

**/

@Bean

public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(

final ObjectProvider> 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 list = new ArrayList<>(

restTemplate.getInterceptors());

// 在原有的拦截器的基础上 添加了一个 LoadBalancerInterceptor

list.add(loadBalancerInterceptor);

// 然后将添加有新的 拦截器的集合 设置到了 RestTemplate 对象中

restTemplate.setInterceptors(list);

};

}

}

// 省略其他代码

}

通过对应的备注大家可以搞清楚该配置类的作用是实现了对【RestTemplate】对象(被@LoadBalanced修饰)植入【LoadBalancerInterceptor】拦截器的功能。

总结

Ribbon系统时的操作

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注我们的更多内容!


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:什么是DOS攻击?DOS攻击常见形式是什么?(什么攻击属于dos攻击)
下一篇:Meterpreter入门与精通(十三)(十四)(meterpreter是什么意思)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~