Springboot3.0源码揭秘 --BootstrapContext的创建及初始化

DefaultBootstrapContext bootstrapContext = createBootstrapContext();

createBootstrapContext的方法如下


java

代码解读

复制代码

private DefaultBootstrapContext createBootstrapContext() { DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); // 调用Initializers this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext)); return bootstrapContext; }

通过createBootStrapContext()方法最终创建了DefaultBootstrapContext,我们先来看看DefaultBootstrapContext所实现的接口有哪些。

从上图可以可以看到,DefaultBootstrapContext实现了ConfigurableBootstrapContext,而ConfigurableBootstrapContext只是简单的继承了上层的两接口,相当于把他们融合在一起。

我们核心要关注的还是上层的两个接口的作用是啥,其实从命名也可以看出一二:一个主要负责Context,一个复杂注册。我们还是照着之前的习惯,通过代码的注释来看看

BootstrapRegistry在之前【Springboot3.0源码揭秘 -- BootstrapRegistryInitializer拓展点的作用及其应用】一文中,我们已经了解过它的作用。接着我们来看看BootstrapContext

通过类头的注释,我们可以了解到:

这是一个简单的引导上下文,在启动期间以及 {@link Environment} 后处理阶段,直到 {@link ApplicationContext} 准备好为止。

它提供对创建成本较高的单例对象的懒加载访问,或者在 {@link ApplicationContext} 可用之前需要共享的单例对象。

同样的,我们也简单看看BootstrapContext中各个方法的作用:

我们可以看到,BootstrapContext接口中定义的方法有这个几个get、getOrElse、getOrElseSupply、getOrElseThrow、isRegistered,除isRegistered是判断BootstrapContext是否有对应的实例外,其他方法均是通过指定的类型,到BootstrapContext中去获取对应的实例。只是他们的实现有略微的差异,我们可以通过具体的实现类看看。

目前,BootstrapContext在springboot中的实现有且只有一个,就是DefaultBootstrapContext。DefaultBootstrapContext实现了BootstrapRegistry、BootstrapContext中的方法

为什么说BootstrapContext是一个简单引导上下文呢?比起ApplicantContext的实现,它确实足够的简单:

DefaultBootstrapContext类中,有两个map,instances用来存储实例化好的的实例,而instanceSuppliers用来存储用了创建实例的supplier。当我们通过register注册的时候,其实是往instanceSuppliers中进行注册,大家应该还记得之前的demo吧?


java

代码解读

复制代码

registry.register(User.class, InstanceSupplier.of(user));

1.1 实例的注册过程

它调用的就是DefaultBootstrapContext中的register方法,往instanceSuppliers注册


java

代码解读

复制代码

@Override public <T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier) { register(type, instanceSupplier, true); } private <T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier, boolean replaceExisting) { Assert.notNull(type, "Type must not be null"); Assert.notNull(instanceSupplier, "InstanceSupplier must not be null"); synchronized (this.instanceSuppliers) { // 判断是否已经注册,根据入参决定是否替换 boolean alreadyRegistered = this.instanceSuppliers.containsKey(type); if (replaceExisting || !alreadyRegistered) { Assert.state(!this.instances.containsKey(type), () -> type.getName() + " has already been created"); this.instanceSuppliers.put(type, instanceSupplier); } } }

1.2 获取实例的过程

当要使用注册上去的对象时,是通过get方法获取的:


java

代码解读

复制代码

@Override public <T> T get(Class<T> type) throws IllegalStateException { return getOrElseThrow(type, () -> new IllegalStateException(type.getName() + " has not been registered")); } public <T, X extends Throwable> T getOrElseThrow(Class<T> type, Supplier<? extends X> exceptionSupplier) throws X { synchronized (this.instanceSuppliers) { // 从instanceSuppliers获取创造对象的InstanceSupplier,不存在则抛异常 InstanceSupplier<?> instanceSupplier = this.instanceSuppliers.get(type); if (instanceSupplier == null) { throw exceptionSupplier.get(); } return getInstance(type, instanceSupplier); } } private <T> T getInstance(Class<T> type, InstanceSupplier<?> instanceSupplier) { // 先从instances中获取,如果存在则直接返回 T instance = (T) this.instances.get(type); if (instance == null) { // 实例不存在,则调用InstanceSupplier的get方法创建实例,并放入instances中 instance = (T) instanceSupplier.get(this); if (instanceSupplier.getScope() == Scope.SINGLETON) { this.instances.put(type, instance); } } return instance; }

在这个过程中,instances充当缓存的作用,将生成好的对象缓存起来,下次要使用的时候直接拿就可以。

1.3 ApplicationEventMulticaster的作用

DefaultBootstrapContext中三个核心的属性,在实例注册跟获取中我们已经了解了两个,那剩下的ApplicationEventMulticaster有什么用呢?


java

代码解读

复制代码

private final ApplicationEventMulticaster events = new SimpleApplicationEventMulticaster();

这是一个广播类,类似的广播类在springboot中的应用非常广泛。一旦springboot中发生了某些事情,就会通过事件发布出来。这些事件可以通过这个广播类触达到对这类事件感兴趣的类,大家有没有感觉跟设计模式中的观察者模式很像?

可能这样说很抽象,不妨换个场景:小时候村里有点啥事,村子是不是通过村头的广播喊出来:某某区域的群众,请下午两点到村头集合。广播类承担的就是广播的工作,将村子要传播的事情传递出去,再触达到对应的群众那里。

我们在之前的demo中,为了让注册上去的实例可以转到ApplicationContext中,也是通过监听关闭事件来实现的。这个之后的文章会讲到。

2、BootstrapContext的初始化

了解完DefaultBootstrapContext的创建之后,我们继续回到createBootstrapContext方法


java

代码解读

复制代码

private DefaultBootstrapContext createBootstrapContext() { DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); // 调用Initializers this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext)); return bootstrapContext; }

初始化DefaultBootstrapContext之后,紧接着拿到所有的BootstrapRegistryInitializer(这个在SpringApplication初始化的时候已经拿到并设置进去了),接着遍历并调用initialize方法,将bootstrapContext传进去(因为DefaultBootstrapContext实现了BootstrapRegistry、BootstrapContext中的方法),所以这里是相当于BootstrapRegistry传入,最终我们自定义BootstrapRegistryInitializer的时候,是将实例往上面注册的。

至此,BootstrapContext的创建与初始化完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值