spring之bean的生命周期

目录

前言:

什么是Bean?

Bean的生命周期:

1.生成BeanDefinition (扫描,解析,注册,合并)

2.加载类

3.实例化前

4.实例化 doCreatBean

5.BeanDefinition后置处理 (扩展点)

6.实例化后 (扩展点)

7.自动注入( 包括spring自动注入,包括依赖注入)

8.处理属性(就是打了注解的属性) 扩展点

9.执行Aware回调

10.初始化前 扩展点

11. 初始化

12. 初始化后(该步骤会进行AOP) 扩展点

13. Bean的销毁


前言:

         新年新气象,新的一年立个flag,定期整理技术及更新,拒绝松散懈怠!


什么是Bean?

         spring是负责管理bean的,那什么是bean,任何普通的java对象都可以是一个bean,一般常见的有被@Component、@Service、@Repository、@Configuration、@Bean、@Autowired注解修饰的都是被spring所管理。

Bean的生命周期:

1.生成BeanDefinition (扫描,解析,注册,合并)

扫描

      通过扫描.ClassPathScanningCandidateComponentProvider-->findcandidateComponents-->scanCandidateComponents(String basePackage) 扫描某个包路径,并得到BeanDefinition的Set集合。

1. 通过ResourcePatternResolver获得指定包路径下的所有.class 文件(Spring源码中将 此文件包装成了Resource对象)。

2. 遍历每个Resource对象。

3. 利用MetadataReaderFactory解析Resource对象得到MetadataReader(ASM技术),通过利用MetadataReader进行excludeFilters和includeFilters(默认包含的类标记了@Component注解),以及条件注解@Conditional(如果存在会走该注解的逻辑match方法,成功的返回true,失败返回false)的筛选,两个注解有其中一个就会去构造BeanDefinition。

        MetadataReaderFactory具体的实现类为CachingMetadataReaderFactory

        MetadataReader的具体实现类为SimpleMetadataReader

4. 通过筛选的classname赋值给BeanDefinition的beanclass(beanclass这个属性在刚开始扫描时存放的是classname,后边会在加载beanclass所对应的类时存放具体的类对象,这个属性是Object,就是为了处理这两种情况)。基于metadataReader扫描后生成ScannedGenericBeanDefinition。简称sdb对象。

       通过生成的sdb对象会进行一次判断是否是顶级类(没有内部类,或者有静态内部类),是否是接口或者抽象类,是否同时满足是一个接口并且实现了@Lookup注解,满足的会放到candidates结果集中。

解析

5. 遍历得到的BeanDefinition结果集candidates。解析bd对象的注解如(@scope、@component ) 通过判断@component 注解上是否指定了value,根据是否有value来生成beanName(单独的)。同时也会给此时的bd对象设置一些默认的值,比如没有设置是否是懒加载默认设置false。

判断检查spring容器中是否已经存在beanName

        spring还提供了一种快速加载bean的方式,通过配置文件的方式spring.components,然后通过components[index]索引优先加载该bean。       

       此时我们已经有了(beanName,BeanDefiniton对象),然后进行注册。    

注册

合并

在实例化preInstantiateSingletons()方法中去获取合并后的BeanDefiniton

此时bd.isAbstract()为判断是否为抽象的BeanDefinition,if中为合并后的条件

抽象的BeanDefinition (这样定义的话child也是原型的,会继承parent上所定义的scope属性)

        根据child生成Bean对象之前,需要进行BeanDefinition的合并,执行getMergedLocalBeanDefinition(通过递归的方式找到孩子的父亲,父亲的父亲,然后属性覆盖)得到RootBeanDefinition将它存到mergedLocalBeanDefinition ,然后就可以开始创建bean对象。开始创建bean,getBean()当通过传入的名字在单例池中找不到bean的时候就去creatBean

扩展点:当所有的单例bean都创建完成之后可以通过实现该接口的afterxxx方法做一些操作

2.加载类

1. 创建Bean就必须实例化对象,而实例化就必须先加载当前BeanDefinition所对应的class。

    首先进行判断,如果beanClass属性的类型是Class,那么就直接返回。

    如果不是,则会根据类名进行加载 ,如果指定就使用自定义的类加载器。

    如果不指定类加载器的则默认使ClassUtils.getDefaultClassLoader()所返回的类加载器来加载。

ClassUtils.getDefaultClassLoader()

1. 优先返回当前线程中的ClassLoader。

2. 线程中类加载器为null的情况下,返回ClassUtils类的类加载器。

3. 如果ClassUtils类的类加载器为空,那么则表示是Bootstrap类加载器加载的ClassUtils类,那么则返回系统类加载器把类加载进来之后开始实例化前的操作。

3.实例化前

       先判断当前bean对象是否是FactoryBean(定制化Bean工厂),如果是则不走BeanFactory(正常生产Bean工厂)。

       再判断当前的类有没有实现InstantiationAwareBeanPostProcessor此接口,如果实现了此接口那么通过循环找到对应类的InstantiationAwareBeanPostProcessor 会在实例化前去执行postProcessBeforeInstantiation,如果能够在实例化前拿到对象就会直接进入初始化后阶段(有可能AOP),跳过一些步骤,如果没有就会继续执行后续步骤。

       InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 通过此接口允许用户来控制是否在某个或某些Bean 实例化之前做一些启动动作。

4.实例化 doCreatBean

在此阶段找到推断构造方法:

     1. supplier创建对象

     2. 工厂方法创建对象

     3. 推断构造方法

5.BeanDefinition后置处理 (扩展点)

Bean对象实例化出来之后,接下来就应该给对象的属性赋值了。在真正给属性赋值之前,Spring又 提供了一个扩展点MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition(),可以对此时的 BeanDefinition进行加工。

       比如可以加一个初始化方法

6.实例化后 (扩展点)

InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()

检查是否走后续的生命周期

7.自动注入( 包括spring自动注入,包括依赖注入)

指的是Spring的自动注入,比如在@Bean设置autowire = Autowire.BY_NAME 或

Autowire.BY_TYPE 都属于spring的自动注入

下边这种xml方式

根据bytype去找该bean中所有的set方法 ,通过参数类型去找bean并执行该方法

如果是byname得话就是通过set后的名字去找bean

         上边这种配置bean的方式有很大的弊端,就是会找到所有的set方法并且全部都执行,如果用@Autowired那么只会去执行标记了该注解的set方法,可控性好。

8.处理属性(就是打了注解的属性) 扩展点

InstantiationAwareBeanPostProcessor.postProcessProperties()

会解析处理@Autowired、@Resource、@Value、@Lazy等注解

9.执行Aware回调

在初始化方法中先执行Aware回调

判断当前的bean有没有实现Aware接口,如果实现则回调

BeanNameAware:回传beanName给bean对象。

BeanClassLoaderAware:回传classLoader给bean对象。

BeanFactoryAware:回传beanFactory给对象。

10.初始化前 扩展点

回调执行完后找是否有标记了@postConstruct注解的方法,如果有就执行,

ApplicationContextAwareProcessor会在初始化前这个步骤中进行其他Aware的回调

执行完后会去执行BeanPostProcessor.postProcessBeforeInitialization()

11. 初始化

       查看当前Bean对象是否实现了InitializingBean接口,如果实现了就调用其afterPropertiesSet() 方法然后继续判断是否指定了初始化的方法,如果指定了就调用回调去执行。

12. 初始化后(该步骤会进行AOP) 扩展点

      BeanPostProcessor.postProcessAfterInitialization()

      在这个步骤中,对Bean最终进行处理,Spring中的AOP就是基于初始化后实现的,初始化后返 回的对象才是最终的Bean对象。

13. Bean的销毁

Bean销毁是发生在Spring容器关闭过程中的。

在最后(初始化之后),有一个步骤会去判断当前创建的Bean是不是指定了bean销毁的方法

        如果实现 DisposableBean接口或AutoCloseable接口(表示有自己销毁的方法)就需要实现它的 destory() Bean销毁方法。

       如果没有实现那么就会去找看有没有方法标记了@PreDestroy的注解(在初始化前会将@Postcontruct 或 @PreDestroy 这两中注解记录到不同的BeanDefinition中)通过遍历的方式去找到当前bean的销毁方法。

       对有销毁方法的bean通过适配器生成DisposableBeanAdapter对象

       如果指定了在spring容器关闭的时候进行调用。

       如果没有指定销毁方法,spring也会用自己指定的方式来销毁。

Spring容器的关闭过程:(bean的销毁就是在这一步做的)

       先从单例池等缓存中移除Bean。

       在销毁当前Bean的时候,会获取依赖当前Bean的其他Bean进行销毁。

       确保没有其他bean依赖后,根据适配器执行当前bean的销毁方法,根据beanName移除单例池以及清除各种缓存中的该bean信息。

相关推荐

  1. spring bean生命周期

    2024-01-06 17:28:01       58 阅读
  2. Spring Bean生命周期

    2024-01-06 17:28:01       43 阅读
  3. Spring bean生命周期

    2024-01-06 17:28:01       43 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-06 17:28:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-06 17:28:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-01-06 17:28:01       82 阅读
  4. Python语言-面向对象

    2024-01-06 17:28:01       91 阅读

热门阅读

  1. git 使用场景 本地分支 推送到 远程分支

    2024-01-06 17:28:01       76 阅读
  2. CentOS:安装gitlab

    2024-01-06 17:28:01       67 阅读
  3. 2023.12.31力扣每日一题——一年中的第几天

    2024-01-06 17:28:01       69 阅读
  4. pytest常用的第三方插件介绍

    2024-01-06 17:28:01       55 阅读
  5. 根据具体时间转换为一周前、几小时前格式

    2024-01-06 17:28:01       56 阅读
  6. Redis过期清理策略和内存淘汰机制

    2024-01-06 17:28:01       68 阅读
  7. 华为云服务介绍(二)

    2024-01-06 17:28:01       68 阅读
  8. 如何解决大型语言模型的「幻觉」问题

    2024-01-06 17:28:01       65 阅读