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的创建与初始化完毕。