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

目录

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

    一、项目案例准备 首先我们大家案例环境,通过【RestTemplate】来实现服务调用,通过【Ribbon】实现客户端负载均衡操作。
    手把手带你分析SpringBoot自动装配完成了Ribbon哪些核心操作
    文章图片


    1.Order服务
    我们的Order服务作为服务提供者。创建SpringBoot项目,并添加相关依赖
    4.0.0org.springframework.bootspring-boot-starter-parent2.4.9 com.bobo.springcloudspring-cloud-order-server0.0.1-SNAPSHOTspring-cloud-order-serverDemo project for Spring Boot1.8org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-testtestorg.springframework.cloudspring-cloud-dependenciesHoxton.SR10pomimportorg.springframework.bootspring-boot-maven-plugin

    然后在属性文件中添加相关的配置
    spring.application.name=spring-cloud-order-serviceserver.port=8081

    然后创建自定义的Controller 提供对外的服务
    @RestControllerpublic 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项目,添加相关的依赖
    4.0.0org.springframework.bootspring-boot-starter-parent2.3.9.RELEASE com.bobo.springcloudspring-cloud-user-service20.0.1-SNAPSHOTspring-cloud-user-service2Demo project for Spring Boot1.8Hoxton.SR10org.springframework.bootspring-boot-starter-weborg.springframework.cloudspring-cloud-starter-netflix-ribbonorg.springframework.bootspring-boot-starter-testtestorg.springframework.cloudspring-cloud-dependencies${spring-cloud.version}pomimportorg.springframework.bootspring-boot-maven-plugin

    然后在属性文件中配置相关信息
    spring.application.name=spring-cloud-user-servicespring-cloud-order-service.ribbon.listOfServers=localhost:8081,localhost:8082

    然后创建自定义的Controller来实现服务的调用
    @RestControllerpublic class UserController {@Autowiredpublic RestTemplate restTemplate; @AutowiredLoadBalancerClient loadBalancerClient; @Bean@LoadBalancedpublic 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】默认通过轮询的方式来实现了服务的调用

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


    二、Ribbon原理分析 应用比较简单,我们主要是来分析下【Ribbon】的核心原理,先来看看自动装配做了哪些事情。

    1.RibbonAutoConfiguration
    Ribbon在系统启动的时候自动装配完成的设置,我们先来看看对应的spring.factories 中的配置信息吧

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


    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@Qualifierpublic @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; }@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +'}'; }}

    然后定义一个Java配置类,有两个添加了【@LoadBalanced】注解,有一个没有加。
    @Configurationpublic 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"); }}

    然后创建我们的控制器,来测试使用
    @RestControllerpublic class UsersController {@LoadBalanced@AutowiredList list = Collections.emptyList(); @GetMapping("/querys")public String query(){return list.toString(); }}

    项目结构

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

    启动SpringBoot项目后我们看效果

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

    搞清楚了【@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 并注入到了容器中**/@Beanpublic LoadBalancerInterceptor loadBalancerInterceptor(LoadBalancerClient loadBalancerClient,LoadBalancerRequestFactory requestFactory) {return new LoadBalancerInterceptor(loadBalancerClient, requestFactory); }/***3. *创建了一个 RestTemplateCustomizer 并注入到了容器中*而且通过内部类的方式定义定义了 RestTemplateCustomizer 接口中的 customize 方法的逻辑**/@Bean@ConditionalOnMissingBeanpublic RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {return restTemplate -> {// 获取 RestTemplate 中原有的 拦截器List list = new ArrayList<>(restTemplate.getInterceptors()); // 在原有的拦截器的基础上 添加了一个 LoadBalancerInterceptorlist.add(loadBalancerInterceptor); // 然后将添加有新的 拦截器的集合 设置到了 RestTemplate 对象中restTemplate.setInterceptors(list); }; } }// 省略其他代码}

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

    总结 Ribbon系统时的操作

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

    【手把手带你分析SpringBoot自动装配完成了Ribbon哪些核心操作】本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

      推荐阅读