专栏目录
31. FeignClient 实现断路器以及线程隔离限流的思路 5.所有项目的parent与spring-framework-common说明 19.Eureka的服务端设计与配置 16.Eureka架构和核心概念 36. 验证断路器正确性 28.OpenFeign的生命周期-进行调用 4.maven依赖回顾以及项目框架结构 40. spock 单元测试封装的 WebClient(上) 38. 实现自定义 WebClient 的 NamedContextFactory 1. 背景 37. 实现异步的客户端封装配置管理的意义与设计 35. 验证线程隔离正确性 29.Spring Cloud OpenFeign 的解析(1) 41. SpringCloudGateway 基本流程讲解(2) 44.避免链路信息丢失做的设计(1) 14.UnderTow AccessLog 配置介绍 15.UnderTow 订制 40. spock 单元测试封装的 WebClient(下) 17.Eureka的实例配置 7.从Bean到SpringCloud 6.微服务特性相关的依赖说明 12.UnderTow 简介与内部原理 11.Log4j2 监控相关 21.Spring Cloud LoadBalancer简介 22.Spring Cloud LoadBalancer核心源码 20. 启动一个 Eureka Server 集群 23.订制Spring Cloud LoadBalancer 8.理解 NamedContextFactory 24.测试Spring Cloud LoadBalancer 30. FeignClient 实现重试 43.为何 SpringCloudGateway 中会有链路信息丢失 41. SpringCloudGateway 基本流程讲解(1) 39. 改造 resilience4j 粘合 WebClient 44.避免链路信息丢失做的设计(2) 18.Eureka的客户端核心设计和配置 27.OpenFeign的生命周期-创建代理 42.SpringCloudGateway 现有的可供分析的请求日志以及缺陷 25.OpenFeign简介与使用 10.使用Log4j2以及一些核心配置 26.OpenFeign的组件 33. 实现重试、断路器以及线程隔离源码 13.UnderTow 核心配置 32. 改进负载均衡算法 3.Eureka Server 与 API 网关要考虑的问题 45. 实现公共日志记录 2.微服务框架需要考虑的问题 9.如何理解并定制一个Spring Cloud组件 34.验证重试配置正确性

9.如何理解并定制一个Spring Cloud组件

干货满满张哈希
• 阅读 1119

9.如何理解并定制一个Spring Cloud组件

本系列为之前系列的整理重启版,随着项目的发展以及项目中的使用,之前系列里面很多东西发生了变化,并且还有一些东西之前系列并没有提到,所以重启这个系列重新整理下,欢迎各位留言交流,谢谢!~

我们实现的 Spring Cloud 微服务框架,里面运用了许多 Spring Cloud 组件,并且对于某些组件进行了个性化改造。那么对于某个 Spring Cloud 组件,我们一般是如何入手理解其中的原理呢?以及如何知道其中的扩展点呢?一般从下面两个方面入手:

  1. 通过 spring-boot SPI 机制查看模块的扩展点
  2. 查看该模块实现的 NamedContextFactory

9.如何理解并定制一个Spring Cloud组件

spring-core 项目中提供了 Spring 框架多种 SPI 机制,其中一种非常常用并灵活运用在了 Spring-boot 的机制就是基于 spring.factories 的 SPI 机制。

那么什么是 SPI(Service Provider)呢? 在系统设计中,为了模块间的协作,往往会设计统一的接口供模块之间的调用。面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码,而是将指定哪个实现置于程序之外指定。Java 中默认的 SPI 机制就是通过 ServiceLoader 来实现,简单来说就是通过在META-INF/services目录下新建一个名称为接口全限定名的文件,内容为接口实现类的全限定名,之后程序通过代码:

//指定加载的接口类,以及用来加载类的类加载器,如果类加载器为 null 则用根类加载器加载
ServiceLoader<SpiService> serviceLoader = ServiceLoader.load(SpiService.class, someClassLoader);
Iterator<SpiService> iterator = serviceLoader.iterator();
while (iterator.hasNext()){
    SpiService spiService = iterator.next();
}

获取指定的实现类。

在 Spring 框架中,这个类是SpringFactoriesLoader,需要在META-INF/spring.factories文件中指定接口以及对应的实现类,例如 Spring Cloud Commons 中的:

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.client.HostInfoEnvironmentPostProcessor

其中指定了EnvironmentPostProcessor的实现HostInfoEnvironmentPostProcessor

同时,Spring Boot 中会通过SpringFactoriesLoader.loadXXX类似的方法读取所有的EnvironmentPostProcessor的实现类并生成 Bean 到 ApplicationContext 中:

EnvironmentPostProcessorApplicationListener

//这个类也是通过spring.factories中指定ApplicationListener的实现而实现加载的,这里省略
public class EnvironmentPostProcessorApplicationListener implements SmartApplicationListener, Ordered {
    //创建这个Bean的时候,会调用
    public EnvironmentPostProcessorApplicationListener() {
        this(EnvironmentPostProcessorsFactory
                .fromSpringFactories(EnvironmentPostProcessorApplicationListener.class.getClassLoader()));
    }
}

EnvironmentPostProcessorsFactory

static EnvironmentPostProcessorsFactory fromSpringFactories(ClassLoader classLoader) {
    return new ReflectionEnvironmentPostProcessorsFactory(
            //通过 SpringFactoriesLoader.loadFactoryNames 获取文件中指定的实现类并初始化
            SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class, classLoader));
}

9.如何理解并定制一个Spring Cloud组件

META-INF/spring.factories 文件中不一定指定的是接口以及对应的实现类,例如:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration,\
org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration,\

其中EnableAutoConfiguration是一个注解,LoadBalancerAutoConfigurationBlockingLoadBalancerClientAutoConfiguration都是配置类并不是EnableAutoConfiguration的实现。那么这个是什么意思呢?EnableAutoConfiguration是一个注解,LoadBalancerAutoConfigurationBlockingLoadBalancerClientAutoConfiguration都是配置类。spring.factories这里是另一种特殊使用,记录要载入的 Bean 类。EnableAutoConfiguration在注解被使用的时候,这些 Bean 会被加载。这就是spring.factories的另外一种用法。

EnableAutoConfiguration是 Spring-boot 自动装载的核心注解。有了这个注解,Spring-boot 就可以自动加载各种@Configuration注解的类。那么这个机制是如何实现的呢?

来看下EnableAutoConfiguration的源码 EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    //排除的类
    Class<?>[] exclude() default {};
    //排除的Bean名称
    String[] excludeName() default {};
}

我们看到了有 @Import 这个注解。这个注解是 Spring 框架的一个很常用的注解,是 Spring 基于 Java 注解配置的主要组成部分。

9.如何理解并定制一个Spring Cloud组件

  1. 查看 jar 包的 META-INF/spring.factories
  2. 查看里面的内容,尤其关注 org.springframework.boot.autoconfigure.EnableAutoConfiguration= 自动加载的配置类
  3. 查看自动加载的配置类,关注哪些 Bean 可以扩展(例如,包含@ConditionalOnMissingBean 注解的 Bean)

9.如何理解并定制一个Spring Cloud组件

我们一般想个性化定制都是针对调用不同微服务不同的 Bean 配置,所以其实要重点关注的就是这个模块扩展的 NamedContextFactory:

  1. 寻找这个组件扩展 NamedContextFactory 的类
  2. 查看类的源代码,查看默认配置是什么类,以及 Specification 是什么类,以及如何获取当前微服务的名称。
  3. 根据默认配置类,查看里面的 Bean 有哪些,并且哪些可以被替换(例如,包含@ConditionalOnMissingBean 注解的 Bean)
  4. 根据 Specification 查看扩展配置的方式

我们这里拿 spring-cloud-loadbalancer 举一个简单例子,即:

spring-cloud-loadbalancer 中扩展 NamedContextFactory 的类是 LoadBalancerClientFactory,查看 LoadBalancerClientFactory 的代码可以知道:

9.如何理解并定制一个Spring Cloud组件

  1. 可以通过 loadbalancer.client.name 这个属性获取当前要创建的 Bean 是哪个微服务的
  2. 可以知道默认配置是 LoadBalancerClientConfiguration,再查看它里面的源代码我们可以知道主要初始化两个 Bean:
    1. ReactorLoadBalancer,负载均衡器,因为有 @ConditionalOnMissingBean 所以可以被替换,这就是我们的扩展点
    2. ServiceInstanceSupplier,提供实例信息的 Supplier,因为有 @ConditionalOnMissingBean 所以可以被替换,这就是我们的扩展点
  3. Specification 为 LoadBalancerSpecification,再分析其调用可以知道,可以通过 @LoadBalancerClient@LoadBalancerClientsLoadBalancerClientConfiguration 的基础上额外指定配置。

9.如何理解并定制一个Spring Cloud组件

我们这一节详细分析了如何使用以及分析改造一个 Spring Cloud 组件。下一节我们将开始具体分析我们实现的微服务框架的每一块功能。

微信搜索“我的编程喵”关注公众号,每日一刷,轻松提升技术,斩获各种offer

9.如何理解并定制一个Spring Cloud组件

点赞
收藏
评论区
推荐文章

暂无数据