Spring容器生命周期

Spring容器生命周期

执行ConfigurableApplicationContext.refresh() 方法是Spring容器生命周期开始的主要入口点. 而调用BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor两个后置处理是最重要的一个步骤,因为会触发ConfigurationClassPostProcessor执行postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法,实现classpath下指定包中的类文件扫描。
在这里插入图片描述

认识BeanDefinition

BeanDefinition是一个接口,用于描述Bean的信息,例如有哪些属性,构造方法参数,bean的作用域,是否懒加载等。当调用applicationContext.getBean(…)获取Bean实例对象时,如果Bean还没有创建,则会通过BeanDefinition中的描述信息创建Bean,BeanDefinition有如下几个重要的实现类.
在这里插入图片描述

  1. 启动类使用了AnnotatedGenericBeanDefinition封装。
  2. classpath下执行包扫描被扫描到的类使用: ScannedGenericBeanDefinition,在ClassPathScanningCandidateComponentProvider 418行即可看到。
  3. 被导入的bean使用 AnnotatedGenericBeanDefinition
    例如: 通过spring.factories配置的类是被启动类导入的Bean, 非静态的内部配置类在org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader 137行断点即可看到
  4. 通过@Bean方法配置的bean使用 ConfigurationClassBeanDefinition
    当调用applicationContext.getBean()获取Bean时,如果bean对象还未创建则,会调用AbstractBeanFactory.getMergedLocalBeanDefinition()将不同类型的BeanDefinition转成RootBeanDefinition

认识BeanFactoryPostProcessor

中文翻译为Bean工厂后置处理器,开发者可以通过实现该接口,在其接口方法postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)中通过beanFactory修改已存在的BeanDefinition属性,也可以用于手动添加自定义的BeanDefinition

BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor的子类,添加了postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法,两个接口方法作用基本相同。
但是子类中的postProcessBeanDefinitionRegistry(…)方法在父类的postProcessBeanFactory(…)方法之前执行.
在这里插入图片描述

2.1 调用prepareRefresh() 方法激活容器

调用该方法仅是为了将AbstractApplicationContext中的AtomicBoolean active成员变量值设置成true,表示Spring容器激活,可以调用applicationContext.getBean(…)方法,在此之前调用都将抛出”has not been refreshed yet”异常.

2.2 设置ConfigurableListableBeanFactory对象所需要的必要组件

prepareBeanFactory(ConfigurableListableBeanFactory beanFactory)这个方法主要用于向beanFactory中添加一些必要的初始化组件:

  1. 添加SpringEL表达式解析器
  2. 添加ApplicationContextAwareProcessor后置处理器,当实例化Bean时用于检测其是否实现Aware方法,实现注入。
  3. 添加ApplicationListenerDetector后置处理器,用于检测bean是否实现了ApplicationListener,如果是则添加到AbstractApplicationContext的监听器集合中。

2.3 调用BeanFactoryPostProcessor,实现包扫描

  1. 获取AbstractApplicationContext中成员变量beanFactoryPostProcessors保存的BeanFactoryPostProcessor, 遍历调用BeanDefinitionRegistryPostProcessor接口实现类. 此时只有三个BeanFactoryPostProcessor实现类,但是只有前两个是实现了BeanDefinitionRegistryPostProcessor接口。
    A. CachingMetadataReaderFactoryPostProcessor
    注册SharedMetadataReaderFactoryBean工厂bean,其实现了FactoryBean接口,主要用于在类路径下class文件扫描时读取类信息,相关类: SimpleMetadataReaderClassPathScanningCandidateComponentProvider

    B. ConfigurationWarningsPostProcessor
    用于对启动类上设置的扫描包进行验证,用户设置的扫描包不能是: org.springframeworkorg,否则抛出异常.

    C. PropertySourceOrderingPostProcessor
    PropertySourceOrderingPostProcessor仅实现了BeanFactoryPostProcessor,目的将ConfigurableEnvironment中的名称为”defaultProperties”的PropertySource放在集合最后

  2. 通过beanFactory.getBeanNamesForType(…)获取Spring容器中实现BeanDefinitionRegistryPostProcessor接口的类名称集合并遍历,如果bean同时是PriorityOrdered接口的实现类,则通过getBean()获取实例对象,此时容器中只有一个ConfigurationClassPostProcessor主要用于类路径下文件扫描.

  3. 调用ConfigurationClassPostProcessor实现的postProcessBeanDefinitionRegistry()方法,开始执行类路径扫描。通过SimpleMetadataReader指定包下的class文件,如果扫描到的类是一个配置类,或者是通过@Import注解导入的类会采用递归的方式继续判断是否是配置类,直到是解析到普通的Bean,然后通过this.reader.loadBeanDefinitions(configClasses),过滤得到符合条件注解要求的BeanDefinition

  4. 因为执行完类路径扫描后,可能有实现BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor接口的Bean,所以需要再次通过beanFactory.getBeanNamesForType(…)获取Spring中实现BeanDefinitionRegistryPostProcessor接口的类名称集合,去除已经调用过的实现类ConfigurationClassPostProcessor,遍历bean名称获取实现了Ordered接口的实例,排序后回调接口方法

  5. 在while(reiterate) 中遍历调用没有实现排序接口BeanDefinitionRegistryPostProcessor的bean。

    为什么要用while语句? 为了防止在回调方法中注入一个新的BeanDefinitionRegistryPostProcessor实现类.这样可以调用新的BeanDefinitionRegistryPostProcessor

  6. 回调BeanDefinitionRegistryPostProcessor父类BeanFactoryPostProcessor的方法postProcessBeanFactory(beanFactory) 无排序

  7. 获取BeanFactoryPostProcessor接口实现类,按照排序接口类型分类排序,回调接口方法

    • 遍历执行实现org.springframework.core.PriorityOrdered排序的BeanFactoryPostProcessor
    • 遍历执行实现org.springframework.core.Ordered排序的BeanFactoryPostProcessor
    • 遍历执行未实现排序接口的BeanFactoryPostProcessor

2.4 注册BeanPostProcessors用于处理bean

  1. 通过beanFactory.getBeanNamesForType(…)获取BeanPostProcessor类型的beanName集合

  2. 遍历beanNames,按照排序接口类型分类并排序,如果是MergedBeanDefinitionPostProcessor实现类,也将独立保存到一个集合中,这接口主要用于Spring内部使用.最后得到如下三个集合,通过abstractBeanFactory.addBeanPostProcessor(postProcessor)保存BeanPostProcessor

  3. 添加ApplicationListenerDetector,用于收集事件监听器实现类,将其添加到AbstractApplicationContext的applicationListeners集合中

    注意点: 注册BeanPostProcessor时,会调用getBean(beanName)获取BeanPostProcessor实例对象,而getBean()方法内部又会调用已经存在的BeanPostProcessor处理新创建的Bean,因此先注册的BeanPostProcessor可能会处理后注册的BeanPostProcessor,例如:
    实现PriorityOrdered接口的BeanPostProcessor会处理后注册的实现OrderedBeanPostProcessor
    实现Ordered接口的BeanPostProcessor会处理后注册的没有实现排序接口的BeanPostProcessor

2.5 注册事件广播器到Spring容器

initApplicationEventMulticaster()方法通过beanFactory.registerSingleton()向Spring容器注册事件广播器,用于广播事件

2.6 注册事件监听器

用于加载开发者通过注解配置的监听器,只能监听ContextRefreshedEvent之后的事件

2.7 完成所有非懒加载Bean的实例化

finishBeanFactoryInitialization(beanFactory);主要通过获取所有beanName,遍历通过AbstractBeanFactory.getBean(name)方法完成bean的创建. 所有的bean完成实例化之后,重新遍历bean实例,查找实现SmartInitializingSingleton接口的bean,回调接口方法。

2.8 发布ContextRefreshedEvent事件

ContextRefreshedEvent事件在ApplicationStartedEventApplicationReadyEvent事件之前发布。

Spring 容器生命周期可以分为三个阶段:实例化、初始化和销毁。 1. 实例化阶段:在这个阶段,Spring 容器会根据配置文件或注解等方式,创建并实例化所有的 Bean 对象。这个阶段主要包括以下步骤: - 加载配置文件或扫描注解,获取所有的 Bean 定义。 - 根据 Bean 定义创建相应的 Bean 实例。 - 对于单例的 Bean,容器会在这个阶段创建并保留其实例。 2. 初始化阶段:在实例化阶段完成后,Spring 容器会对实例化的 Bean 进行初始化。这个阶段主要包括以下步骤: - 设置 Bean 的属性值,包括依赖注入。 - 调用 Bean 的初始化方法,可以通过配置文件或注解指定初始化方法。 - 执行 BeanPostProcessor 的前置处理方法。 - 对于单例的 Bean,容器会在这个阶段完成其初始化。 3. 销毁阶段:在容器关闭时,会执行销毁阶段,对已经初始化的 Bean 进行销毁和清理工作。这个阶段主要包括以下步骤: - 调用 Bean 的销毁方法,可以通过配置文件或注解指定销毁方法。 - 执行 BeanPostProcessor 的后置处理方法。 需要注意的是,对于单例的 Bean,默认情况下 Spring 容器会管理其完整的生命周期,而对于原型(prototype)作用域的 Bean,则不负责销毁。如果需要在原型 Bean 销毁时执行一些清理工作,可以使用自定义的销毁回调方法或者手动管理。 以上是 Spring 容器的基本生命周期,可以通过配置文件或注解等方式来控制和管理 Bean 的生命周期
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值