Bean的生命周期(一)

简介: Bean的生命周期

Bean的生命周期

前言

1、什么是Bean的生命周期?

2、Bean的生命周期是怎样的?

什么是Bean的生命周期

我们知道,在Java中,万物皆对象,这些对象有生命周期:实例化 -> gc回收

而Bean同样也是Java中的对象,只是在这同时,Spring又赋予了它更多的意义。

于是乎,我们将Bean从在Spring中创建开始,到Bean被销毁结束,这一过程称之为Bean的生命周期

那到底Bean在Spring中的创建过程是怎样的呢?

Bean的生命周期是怎样的

在Spring中,Bean的创建过程看起来复杂,但实际上逻辑分明。

如果我们将所有扩展性流程抛开,你会发现只剩下两个流程:对象的实例化和属性填充

我们在《从依赖倒置原则看Spring》文中手写的Spring,也只是完成了这两个流程,这足以说明只需要这两个流程就能完成一个简单的Spring框架,那其他的流程又是什么呢?他们又有什么作用?

那么我们现在就基于这两个核心流程出发,尝试完善整个Spring的Bean生命周期。

推导过程

开始时,我们只有两个流程:对象的实例化和属性填充

我们知道,对象的实例化就是在Java里使用类构造器进行创建对象。而一个类中可能有很多的构造器,那么我们怎么才能知道使用哪个构造器进行实例化对象呢?

所以说,在实例化之前,还得先做一件事情:确定候选的构造器,也称之为构造器推断

构造器推断

功能描述:找寻beanClass中所有符合候选条件的构造器。

负责角色:AutowiredAnnotationBeanPostProcessor

候选条件:构造器上添加了@Autowired注解

推断流程:

1、获取beanClass中的所有构造器进行遍历,判断构造器上是否标识@Autowired注解,是则将构造器添加到候选构造器集合中

2、并进一步判断Autowired注解中required属性是否为true(默认为true),是则表示该beanClass已存在指定实例化的构造器,不可再有其他加了@Autowired注解的构造器,如果有则抛出异常。

3、如果Autowired注解中required属性为false,则可继续添加其他@Autowired(required=false)标识的构造器

4、如果候选构造器集合不为空(有Autowired标识的构造器),并且beanClass中还有个空构造器,那么同样将空构造器也加入候选构造器集合中。

5、如果候选构造器集合为空,但是beanClass中只有一个构造器且该构造器有参,那么将该构造器加入候选构造器集合中。

流程图:

当构造器遍历完毕之后,还有些许逻辑

以上判断条件很多,但始终是围绕这一个逻辑:这个beanClass中有没有被Autowired标识的构造器,有的话required是true还是false,如果是true, 那其他的构造器都不要了。如果是false,那想加多少个构造器就加多少个。

咦,那要是没有Autowired标识的构造器呢?

框架嘛,都是要兜底的,这里就是看beanClass中是不是只有一个构造器且是有参的。

那我要是只有个无参的构造器呢?

那确实就是没有候选的构造器了,但是Spring最后又兜底了一次,在没有候选构造器时默认使用无参构造器

那我要是有很多个构造器呢?

Spring表示那我也不知道用哪个呀,同样进入兜底策略:使用无参构造器(没有将抛出异常)

那么这就是构造器推断流程了,我们将它加入到流程图中

在得到候选的构造器之后,就可以对对象进行实例化了,那么实例化的过程是怎样的呢?

对象实例化

功能描述:根据候选构造器集合中的构造器优先级对beanClass进行实例化。

负责角色:ConstructorResolver

对象实例化的过程主要有两个方面需要关注:

1、构造器的优先级是怎样的?

2、如果有多个构造器,但是有部分构造器的需要的bean并不存在于Spring容器中会发生什么?也就是出现了异常怎么处理?

1. 构造器的优先级是怎样的?

在Java中,多个构造器称之为构造器重载,重载的方式有两种:参数的数量不同,参数的类型不同。

在Spring中,优先级则是由构造器的修饰符(public or private)和参数的数量决定。

规则如下:

1、public修饰的构造器 > private修饰的构造器

2、修饰符相同的情况下参数数量更多的优先

这段流程很简单,代码只有两行:

// 如果一个是public,一个不是,那么public优先
int result = Boolean.compare(Modifier.isPublic(e2.getModifiers()), Modifier.isPublic(e1.getModifiers()));
// 都是public,参数多的优先
return result != 0 ? result : Integer.compare(e2.getParameterCount(), e1.getParameterCount());

文中描述的规则是public > private, 只是为了更好的理解,实际上比较的是public和非public

2. Spring是如何处理实例化异常的?

当一个beanClass中出现多个构造器,但是有部分构造器的需要的bean并不存在于Spring容器中,此时会发生什么呢?

比如以下案例中,InstanceA具有三个构造方法,其中InstanceB并未注入到Spring中

@Component
public class InstanceA {
  @Autowired(required = false)
  public InstanceA(InstanceB instanceB){
    System.out.println("instance B ...");
  }
  @Autowired(required = false)
  public InstanceA(InstanceC instanceC){
    System.out.println("instance C ...");
  }
  @Autowired(required = false)
  public InstanceA(InstanceB instanceB, InstanceC instanceC, InstanceD InstanceD){
    System.out.println("instance B C D...");
  }
}

那么启动时是报错呢?还是选择只有InstanceC的构造器进行实例化?

运行结果会告诉你:Spring最终使用了只有InstanceC的构造器

这一部分的具体过程如下:

1、将根据优先级规则排序好的构造器进行遍历

2、逐个进行尝试查找构造器中的需要的bean是否都在Spring容器中,如果成功找到将该构造器标记为有效构造器,并立即退出遍历

3、否则记录异常继续尝试使用下一个构造器

4、当所有构造器都遍历完毕仍未找到有效的构造器,抛出记录的异常

5、使用有效构造器进行实例化

推导过程

到这里,beanClass实例化了一个bean,接下来需要做的便是对bean进行赋值,但我们知道,Spring中可以进行赋值的对象不仅有通过@Autowired标识的属性,还可以是@Value,@Resource,@Inject等等。

为此,Spring为了达到可扩展性,将获取被注解标识的属性的过程与实际赋值的过程进行了分离。

该过程在Spring中被称为处理beanDefinition

处理beanDefinition

功能描述:处理BeanDefintion的元数据信息

负责角色:

1、AutowiredAnnotationBeanPostProcessor: 处理@Autowird,@Value,@Inject注解

2、CommonAnnotationBeanPostProcessor:处理@PostConstruct,@PreDestroy,@Resource注解

这两个后置处理器的处理过程十分类似, 我们以AutowiredAnnotationBeanPostProcessor为例:

1、遍历beanClass中的所有FieldMethod(java中统称为Member

2、判断Member是否标识@Autowird,@Value,@Inject注解

3、是则将该Member保存,封装到一个叫做InjectionMetadata的类中

4、判断Member是否已经被解析过,比如一个Member同时标识了@Autowired@Resource注解,那么这个Member就会被这两个后置处理器都处理一遍,就会造成重复保存

5、如果没被解析过就将该Member放置到已检查的元素集合中,用于后续填充属性时从这里直接拿到所有要注入的Member

其中,AutowiredAnnotationBeanPostProcessorInjectionMetadata的结构如下

同样,我们将这一部分流程也加入到流程图中

现在,beanClass中的可注入属性都找出来了,接下来就真的要进行属性填充了


目录
相关文章
|
7月前
|
前端开发 Java 开发者
Bean的生命周期和作用域
Bean的生命周期和作用域
|
3月前
|
Java 开发者 Spring
Bean生命周期介绍
Spring Boot 的 Bean 生命周期管理是其核心功能之一,负责应用程序中 Java 对象(称为 Beans)的创建、配置、初始化和销毁。此功能提供了灵活的依赖注入方式,便于组件化开发。Bean 生命周期包括实例化、属性注入、初始化方法调用、使用及销毁方法调用等阶段。应用场景涵盖依赖注入、配置管理、组件扩展及切面编程。通过实现特定接口或注解,开发者可轻松管理对象生命周期,优化应用性能。示例代码展示了如何通过日志观察 Bean 生命周期的不同阶段。
120 3
|
7月前
|
存储 设计模式 Java
Bean 作用域和生命周期
Bean 作用域和生命周期
|
Java 容器 Spring
Bean生命周期
Bean生命周期
|
7月前
|
Java 开发者 Spring
Bean 的生命周期了解么
Bean 的生命周期了解么
|
Java Spring 容器
bean的生命周期
bean的生命周期
57 0
|
缓存 前端开发 Java
Spring源码:Bean生命周期(四)
在本文中,我们深入探讨了 Spring 框架中 Bean 的实例化过程,关于某些细节以后我会单独拿出一篇文章单独讲解,我们来总结下实例化都做了哪些事情:先从bean定义中加载当前类,因为最初Spring使用ASM技术解析元数据时只获取了当前类的名称寻找所有InstantiationAwareBeanPostProcessors实现类,并调用实例化前的方法postProcessBeforeInstantiation进行实例化,这里会使用构造方法进行实例化调用applyMergedBeanDefinitionPostProcessors找到所有MergedBeanDefinitionPostPro
|
存储 安全 Java
Bean 的作用域和生命周期
Bean 的作用域和生命周期
78 1
|
XML Java 数据格式
Bean 的生命周期
Bean 的生命周期介绍
Bean的生命周期
Bean的生命周期
54 0