【Spring Boot 源码学习】BootstrapRegistry 初始化器实现

《Spring Boot 源码学习系列》

在这里插入图片描述

一、引言

前面的博文《BootstrapRegistryInitializer 详解》,Huazie 带大家一起详细分析了 Spring Boot 启动时加载并初始化 BootstrapRegistryInitializer 及其相关的类的逻辑。本篇就让我们自定义 BootstrapRegistryInitializer 接口实现,以此来执行自定义的初始化操作【如注册自定义的 Bean、添加 BootstrapContext 关闭监听器】。

在这里插入图片描述

二、往期内容

在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】:

Spring Boot 源码学习
Spring Boot 项目介绍
Spring Boot 核心运行原理介绍
【Spring Boot 源码学习】@EnableAutoConfiguration 注解
【Spring Boot 源码学习】@SpringBootApplication 注解
【Spring Boot 源码学习】走近 AutoConfigurationImportSelector
【Spring Boot 源码学习】自动装配流程源码解析(上)
【Spring Boot 源码学习】自动装配流程源码解析(下)
【Spring Boot 源码学习】深入 FilteringSpringBootCondition
【Spring Boot 源码学习】OnClassCondition 详解
【Spring Boot 源码学习】OnBeanCondition 详解
【Spring Boot 源码学习】OnWebApplicationCondition 详解
【Spring Boot 源码学习】@Conditional 条件注解
【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解
【Spring Boot 源码学习】RedisAutoConfiguration 详解
【Spring Boot 源码学习】JedisConnectionConfiguration 详解
【Spring Boot 源码学习】初识 SpringApplication
【Spring Boot 源码学习】Banner 信息打印流程
【Spring Boot 源码学习】自定义 Banner 信息打印
【Spring Boot 源码学习】BootstrapRegistryInitializer 详解
【Spring Boot 源码学习】ApplicationContextInitializer 详解
【Spring Boot 源码学习】ApplicationListener 详解
【Spring Boot 源码学习】SpringApplication 的定制化介绍
【Spring Boot 源码学习】BootstrapRegistry 详解
【Spring Boot 源码学习】深入 BootstrapContext 及其默认实现

三、主要内容

注意: 以下涉及 Spring Boot 源码 均来自版本 2.7.9,其他版本有所出入,可自行查看源码。

3.1 BootstrapRegistry

《BootstrapRegistry 详解》 中,Huazie 详细介绍了 BootstrapRegistry 的源码,这有助于下面介绍的 BootstrapRegistry 初始化器的实现逻辑,有不知道的朋友们直接查看即可,这里不再赘述。

3.2 BootstrapRegistryInitializer

《BootstrapRegistryInitializer 详解》 中,Huazie 详解分析了加载并初始化 BootstrapRegistryInitializer 的逻辑,这同样有助于
理解下面将要讲解的内容,还不熟悉的朋友们赶紧花点时间了解下,这里不再赘述。

3.3 BootstrapRegistry 初始化器实现

3.3.1 定义 DemoBootstrapper

下面我们来定义一个类 DemoBootstrapper,该类实现 BootstrapRegistryInitializer 接口,如下:

public class DemoBootstrapper implements BootstrapRegistryInitializer {
    @Override
    public void initialize(BootstrapRegistry registry) {
        // 注册一些自定义的对象 或者 加载自定义的一些配置
    }
}

《BootstrapRegistryInitializer 详解》3.2 小节,Huazie 介绍了 BootstrapRegistryInitializer 的加载过程,上述我们自定义的 DemoBootstrapper 也会在 Spring Boot 启动引导阶段进行加载并初始化。

上述定义中,我们只是展示了一个空实现的类,其中的 initialize 方法还未做处理。

至于 initialize 方法中该添加哪些逻辑,这就要看它的参数 BootstrapRegistry 接口了。

下面代码,Huazie 演示了如何 注册自定义的对象,以及添加 引导上下文关闭事件监听器

// 注册 User对象,它就是一个简单的 POJO 类,含两个成员变量:名称 name 和年龄 age
registry.register(User.class, context -> new User("Huazie", 18));
// 添加 BootstrapContext关闭 监听器
registry.addCloseListener(new DemoBootstrapContextClosedListener());

DemoBootstrapContextClosedListener ,即引导上下文关闭事件监听器,相关演示代码如下:

public class DemoBootstrapContextClosedListener implements ApplicationListener<BootstrapContextClosedEvent>, Ordered {
    @Override
    public void onApplicationEvent(BootstrapContextClosedEvent event) {
        BootstrapContext bootstrapContext = event.getBootstrapContext();
        if (bootstrapContext.isRegistered(User.class)) {
            System.out.println("BootstrapContext关闭时获取User:" + bootstrapContext.get(User.class));
        }
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

虽然上面添加了引导上下文关闭事件监听器,但是我们还不知道什么时候它会被执行。

DemoBootstrapContextClosedListener 中,我们看到了 BootstrapContext 的使用,显然这里涉及到了引导上下文的实际使用场景,由于篇幅受限,将在下篇介绍,大家不妨期待一下。

另外,在 DemoBootstrapContextClosedListener 中,还看到它实现了 Ordered 接口【spring-core 包中的接口】。

那么在事件监听器中,这个 Ordered 接口是用来做什么的呢?

在回答这个问题之前,我们先来看看 Ordered 接口的源码:

public interface Ordered {
	int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
	int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
	int getOrder();
}

Ordered 接口定义了两个常量和一个方法:

  • HIGHEST_PRECEDENCE:最高优先级值的有用常数【最小的 Integer 值】
  • LOWEST_PRECEDENCE :最低优先级值的有用常数【最大的 Integer 值】
  • int getOrder() :获取当前对象的优先级值【值越小,优先级越高】

源码中对于 Ordered 接口是这样说的:

它可以被需要排序的对象实现,例如在集合中。实际的排序可以被解读为优先级排序,其中第一个对象(即有着最低的排序值)具有最高的优先级。

当然,Ordered 接口还有一个扩展接口,即优先级标记接口 PriorityOrderedPriorityOrdered 对象总是优先于普通 Ordered 对象,无论它们的排序值如何。当对一组 Ordered 对象进行排序时,PriorityOrdered 对象和普通 Ordered 对象实际上被视为两个独立的子集,PriorityOrdered 对象子集先于普通 Ordered 对象子集,并在这些子集内部应用相对排序。

上述排序逻辑请查看 spring-core 包中的 AnnotationAwareOrderComparator 类 和 OrderComparator 类,这里不再赘述了。

现在可以回答上面的问题了:在事件监听器中实现 Ordered 接口,可以用来确保 多个监听同一事件的监听器 可以按照我们 预定的顺序执行

3.3.2 添加 DemoBootstrapper

不过,要想能够加载到自定义的 DemoBootstrapper ,我们还需要将它添加到 bootstrapRegistryInitializers 中才可以。

// SpringApplication的私有变量
private List<BootstrapRegistryInitializer> bootstrapRegistryInitializers;

那么,我们该如何添加呢?

通过阅读 SpringApplication 的源码,可以总结如下的两种方式:

  • META-INF/spring.factories 中添加 org.springframework.boot.BootstrapRegistryInitializer 的配置。这种方式,我们从 《BootstrapRegistryInitializer 详解》3.2 小节可见一斑。

    org.springframework.boot.BootstrapRegistryInitializer=com.example.demo.DemoBootstrapper
    
  • 通过 SpringApplication 中的 addBootstrapRegistryInitializer 方法添加。其实这里在笔者的《SpringApplication 的定制化介绍》中的 1.5 小节也提及过。

    SpringApplication springApplication = new SpringApplication(DemoApplication.class);
    springApplication.addBootstrapRegistryInitializer(new DemoBootstrapper());
    // 其他省略。。。
    

四、总结

本篇 Huazie 介绍了如何自定义 BootstrapRegistry 初始化器实现,其中演示如何在引导上下文中注册了自定义的对象以及如何在引导上下文中添加引导上下文关闭事件监听器

  • 26
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
`DynamicServerListLoadBalancer` 是 Netflix Ribbon 中的一个负载均衡,用于从服务注册中心获取服务列表并进行负载均衡。 在 Spring Boot 中,可以使用 Netflix Ribbon 和 Spring Cloud Netflix 来集成该负载均衡。 具体实现方法如下: 1. 添加 Ribbon 和 Spring Cloud Netflix 依赖 在 pom.xml 文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> ``` 2. 创建一个配置类,并指定负载均衡实现类 ```java @Configuration public class RibbonConfiguration { @Bean public IRule ribbonRule() { // 指定负载均衡实现类为 ZoneAvoidanceRule return new ZoneAvoidanceRule(); } @Bean public IPing ribbonPing() { // 指定负载均衡的心跳检测实现类为 NoOpPing return new NoOpPing(); } } ``` 这里使用 `ZoneAvoidanceRule` 作为负载均衡实现类,默认情况下是使用 `RoundRobinRule`。 3. 在启动类中添加注解 `@RibbonClients` ```java @SpringBootApplication @RibbonClients(defaultConfiguration = RibbonConfiguration.class) public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 这里使用 `@RibbonClients` 注解来指定 Ribbon 的配置类,即 `RibbonConfiguration`。 这样,在 Spring Boot 启动时,就会初始化 `DynamicServerListLoadBalancer`,从注册中心获取服务列表,并进行负载均衡。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Huazie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值