上篇博文《深入 ApplicationContext 初始化器实现》,Huazie 带大家详细分析了 分析 Spring Boot 中预置的应用上下文初始化器实现【即 ApplicationContextInitializer
接口实现类】的源码,了解了在 Spring 容器刷新之前初始化应用程序上下文的一些具体操作。
当然其中有些实现源码比较复杂,还没有深入分析。那本篇就来对其中的
SharedMetadataReaderFactoryContextInitializer
【即 共享 MetadataReaderFactory
上下文初始化器】详细分析下。
注意: 以下涉及 Spring Boot 源码 均来自版本 2.7.9,其他版本有所出入,可自行查看源码。
我们先来看看 SharedMetadataReaderFactoryContextInitializer
的部分源码,如下:
class SharedMetadataReaderFactoryContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
// 其他省略。。。
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
BeanFactoryPostProcessor postProcessor = new CachingMetadataReaderFactoryPostProcessor(applicationContext);
applicationContext.addBeanFactoryPostProcessor(postProcessor);
}
@Override
public int getOrder() {
return 0;
}
// 其他省略。。。
}
从上述源码中,我们可以看出 SharedMetadataReaderFactoryContextInitializer
实现了 ApplicationContextInitializer<ConfigurableApplicationContext>
和 Ordered
接口:
ApplicationContextInitializer<ConfigurableApplicationContext>
:应用上下文初始化器接口类,有关该类的详细介绍,请查看《ApplicationContextInitializer 详解》。Ordered
:实现该接口可以控制应用上下文初始化器实现类的执行顺序,有关这点我们可以查看 SpringApplication
的 getInitializers
方法。
这里排序的关键就是 spring-core 包中提供的 org.springframework.core.annotation.AnnotationAwareOrderComparator
,它能够对实现了 PriorityOrdered
接口、Ordered
接口或被 @Order
注解修饰的类进行统一的排序。
我们继续查看上述 initialize
方法,可以看到这里向应用上下文中添加了一个 BeanFactoryPostProcessor
【 即 CachingMetadataReaderFactoryPostProcessor
】。
我们继续查看 CachingMetadataReaderFactoryPostProcessor
的源码,如下:
从上述截图中,我们可以看出 CachingMetadataReaderFactoryPostProcessor
是一个静态内部类,它同时实现了 PriorityOrdered
和 BeanDefinitionRegistryPostProcessor
接口,有关这两个接口的作用,可以查看 《深入 ApplicationContext 初始化器实现》中的 2.1.1 小节 ,这里不再赘述。
我们继续查看 postProcessBeanDefinitionRegistry
方法,发现这里调用了 register
方法 和 configureConfigurationClassPostProcessor
方法,下面一一介绍:
postProcessBeanDefinitionRegistry
方法是BeanDefinitionRegistryPostProcessor
接口中定义的方法,它用于在标准初始化之后修改应用上下文的内部 bean 定义注册表。所有的常规 bean 定义都将已经被加载,但还没有实例化任何 bean。这允许在下一个后处理阶段开始之前添加更多的 bean 定义。2.2.1 register 方法
首先,进入 register
方法,如下所示:
private void register(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(BEAN_NAME)) {
BeanDefinition definition = BeanDefinitionBuilder
.rootBeanDefinition(SharedMetadataReaderFactoryBean.class, SharedMetadataReaderFactoryBean::new)
.getBeanDefinition();
registry.registerBeanDefinition(BEAN_NAME, definition);
}
}
其中 BEAN_NAME
如下截图所示:
register
方法逻辑简单,它的功能是检查 BeanDefinitionRegistry
中是否已存在名为 BEAN_NAME
的 BeanDefinition
,如果不存在,则创建一个 SharedMetadataReaderFactoryBean
的 BeanDefinition
并将其注册到 registry
中。【有关 SharedMetadataReaderFactoryBean
,可以查看 2.4 小节】
知识点:
BeanDefinitionRegistry
是 Spring 中一个接口,它可以被看作是一个用来管理BeanDefinition
的注册表。BeanDefinition
可以被理解为 Spring 中 Bean 的配置描述,它包含了 Bean 的元数据,如类名、是否为抽象类、构造函数、属性值 等相关信息。这些信息将会告诉 Spring 如何创建和初始化相应的 Bean。
接着,进入 configureConfigurationClassPostProcessor
方法,可见如下截图:
在 configureConfigurationClassPostProcessor(BeanDefinitionRegistry)
方法中,先从 BeanDefinitionRegistry
中获取名为 org.springframework.context.annotation.internalConfigurationAnnotationProcessor
【即内部管理的 Configuration
注解处理器的 bean 名称】的 BeanDefinition
;如果找不到对应的 BeanDefinition
,则捕获 NoSuchBeanDefinitionException
异常后不做任何处理。
知识点:
ConfigurationClassPostProcessor
是 Spring 框架中的一个核心类,它实现了BeanPostProcessor
的子接口BeanDefinitionRegistryPostProcessor
。它的主要作用是解析被@Configuration
注解的类,并将解析到的 Bean 封装为BeanDefinition
注册到 Spring 容器中,以供后续步骤进行统一的实例化。此外,ConfigurationClassPostProcessor
还会处理其他与配置相关的注解,如@Component、@PropertySources、@ComponentScan、@Import
等。
继续进入 configureConfigurationClassPostProcessor(BeanDefinition)
方法中:
从上述截图中,可以看到:
definition
是 AbstractBeanDefinition 的实例
,则调用 configureConfigurationClassPostProcessor(AbstractBeanDefinition)
方法:AbstractBeanDefinition
中获取 bean 的实例提供者 instanceSupplier
。definition
的实例提供者为 2.3 中的自定义供应者 ConfigurationClassPostProcessorCustomizingSupplier
。configureConfigurationClassPostProcessor(MutablePropertyValues)
方法。definition
不是 AbstractBeanDefinition 的实例
,则直接调用 configureConfigurationClassPostProcessor(MutablePropertyValues)
方法。我们继续查看 configureConfigurationClassPostProcessor(MutablePropertyValues)
方法,里面只有一行代码,功能是向 propertyValues
中添加一个新的属性 "metadataReaderFactory"
,其值为一个指向当前上下文中名为 org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory
的 Bean 的引用【RuntimeBeanReference
】。
知识点:
MutablePropertyValues
是 Spring 框架中的一个类,主要用于封装类属性的集合。它是一个 List
容器,包装了多个 PropertyValue
对象,每个 PropertyValue
对象封装了一个属性及其对应的值。当需要在 BeanDefinition
中修改某个类里面的属性时,就可以使用MutablePropertyValues
类。RuntimeBeanReference
是 Spring 框架中用于表示运行时 Bean 引用的一个对象。在 Spring 的 Bean 解析阶段,当解析器遇到需要依赖其他 Bean 的情况时,它会依据依赖 Bean 的名称创建一个RuntimeBeanReference
对象,并将这个对象放入 BeanDefinition
的MutablePropertyValues
中。这个 RuntimeBeanReference
对象是对实际 Bean 的引用,它会在运行时被解析成实际的 Bean 对象。还是一样,先来看看源码:
ConfigurationClassPostProcessorCustomizingSupplier
是一个实现了 Supplier<Object>
接口的自定义供应者类,其包含两个成员变量:
ConfigurableApplicationContext context
:应用上下文对象Supplier<?> instanceSupplier
:原始的 Supplier
,用于获取ConfigurationClassPostProcessor
的实例。通过阅读上述 get
方法,我们可以看到该类在不改变原始 Supplier
逻辑的情况下,对提供的 ConfigurationClassPostProcessor
实例重新设置了 metadataReaderFactory
属性值,而该值是通过调用 context.getBean(BEAN_NAME, MetadataReaderFactory.class)
从 Spring 上下文中获取的一个 MetadataReaderFactory
的 Bean
对象。
话不多说,先来看看相关源码截图:
SharedMetadataReaderFactoryBean
也是一个静态内部类,它实现了 FactoryBean<ConcurrentReferenceCachingMetadataReaderFactory>
、BeanClassLoaderAware
和ApplicationListener<ContextRefreshedEvent>
这三个接口,下面来详细分析下:
FactoryBean
是 Spring 框架中用于创建复杂 Bean 的接口。它包含如下三个方法:
T getObject() throws Exception;
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
getObject()
:该方法用于返回由 FactoryBean 创建的对象实例。这是最核心的方法,通过实现这个方法,可以定义如何创建和返回所需的对象。在 SharedMetadataReaderFactoryBean
中,该方法返回 ConcurrentReferenceCachingMetadataReaderFactory
的实例 metadataReaderFactory
getObjectType()
:该方法用于返回由 FactoryBean 创建的对象的类型,如果事先不知道,则返回 null
。在 SharedMetadataReaderFactoryBean
中,该方法返回CachingMetadataReaderFactory.class
,虽然实际的类型是ConcurrentReferenceCachingMetadataReaderFactory
【这里暂且打个问号,有清楚的朋友可以评论区讨论下】isSingleton()
:该方法用于判断由 FactoryBean 创建的对象是否为单例。如果返回 true
,则表示创建的对象在 Spring IoC 容器中是单例的,即整个应用程序中只有一个实例;如果返回 false
,则表示每次请求都会创建一个新的实例。在 SharedMetadataReaderFactoryBean
中,该方法返回 true
。BeanClassLoaderAware
是 Spring 框架中的一个 Aware
接口,它的主要作用是允许 Bean
在初始化时获取关于自身类加载器的信息,以便执行一些特定的操作,比如动态加载其他类、访问资源等。
该接口只有一个方法:
void setBeanClassLoader(ClassLoader classLoader);
SharedMetadataReaderFactoryBean
实现了该接口,并重写了 setBeanClassLoader
方法,并在该方法中,使用传入的 classLoader
来创建一个新的 ConcurrentReferenceCachingMetadataReaderFactory
实例,然后将其赋值给成员变量 metadataReaderFactory
【如上 2.4 中源码截图中可见 SharedMetadataReaderFactoryBean##getObject()
返回的就是该变量】。
监听器接口 ApplicationListener
,在之前的博文已经介绍过。SharedMetadataReaderFactoryBean
实现了该接口,实现 onApplicationEvent
方法,并监听 ContextRefreshedEvent
事件。当接收到 ContextRefreshedEvent
事件时,就会回调 onApplicationEvent
方法,然后 onApplicationEvent
方法里调用 metadataReaderFactory
的 clearCache
方法来清除缓存。这是为了在应用上下文刷新后确保 MetadataReader
缓存是最新的。
本篇 Huazie 带大家一起分析了 spring-boot-autoconfigure 子模块中预置的 应用上下文初始化器实现 SharedMetadataReaderFactoryContextInitializer
。其中涉及了很多 Spring 的知识,由于篇幅受限没有细说,大家可以查看相关 Spring 文档,并运行 Spring Boot 项目进一步加深理解。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有