spring源码笔记(五) ----Bean的创建流程分析

此处介绍的Bean的创建流程是既没有循环依赖,也没有Aop代理的,通过默认构造创建的Bean的详细调用流程。整个过程由doCreateBean方法进行处理。

 

第一步:通过无参默认构造创建类的实例。

为什么spring中的Bean一定要提供一个无参默认构造呢?因为在上层调用链中,调用

doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)

传入实参为:

doGetBean(name, null, null, false);

第三个参数args这里源码写入固定参数为null;故这里这个null参数原封不动的传入到了createBeanInstance(beanName, mbd, args);第三个参数args中。

createBeanInstance方法内部做了什么?

调用了java.lang.reflect.Contructor中的newInstance方法 。通俗来说,就是通过反射调用默认构造,创建了类的实例。此时仅仅是创建了类的实例,而所有的字段值均为null。

第二步:将Bean对应的BeanFactory添加到第三级缓存singletonFactories中

这里引出了Spring三级缓存的概念,他们分别是单例池:singletonObjects;早期对象缓存:earlySingletonObjects;工厂缓存:singletonFactories;

为什么要这么做?

主要是用来解决循环依赖问题,这个到下一节会有详细的介绍。普通Bean(无循环依赖,无Aop代理)的创建流程仅仅会将Bean添加到工厂缓存中,走个流程,但是没有实际作用。

缓存了什么对象?

工厂缓存,顾名思义:内部缓存的并不是对象本身,缓存的是每个Bean对应的工厂对象。

每个bean都有工厂对象吗?

是的,每个Bean都对应有一个工厂对象。因为spring中的所有bean都是来自同一个函数式接口ObjectFactory中的getObject()方法的返回值

public interface ObjectFactory<T> {
	T getObject() throws BeansException;

}

这个Bean工厂是如何实现的呢?它使用lambda表达式做了不同的实现,它在创建Bean的入口的时候做了一种实现,而在Bean的默认构造调用结束,还未进行DI,要对工厂对象进行缓存的时候用了另一种实现。

第一种实现方式,出现在该Bean还没有开始创建,它的主要作用是用来创建Bean:

sharedInstance = getSingleton(beanName, () -> {
   try {
      return createBean(beanName, mbd, args);
   }
   catch (BeansException ex) {
      destroySingleton(beanName);
      throw ex;
   }
});

 

第二个参数就是对函数式接口ObjectFactory的实现,也就是接口中getObject方法中的方法体。做了什么呢:  createBean(beanName, mbd, args);

如果我们将这个工厂对象做了缓存,那么在解决循环依赖的时候,到时候从第三级缓存中取一个Bean的实例,我们调用getObject方法,实际上,又调用了 createBean(beanName, mbd, args);
哎?是不是创建了两次Bean的实例,这就不是单例的了!故我们缓存工厂对象的时候,要换一个方式!

第二种实现方式:出现在bean已经调用无参构造创建了Bean的实例,而属性还没有填充的时候,这时候,要将Bean添加到第三级缓存(工厂缓存)了,缓存的实现方式是: () -> getEarlyBeanReference(beanName, mbd, bean));

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

顾名思义,真正添加到缓存工厂中的BeanFactory不能具有再创建一个Bean的能力,而是将我们创建好的bean进行一个返回就好了。

因为解决循环依赖,发生在双方的Bean都还没有加入到单例池中,在全部进行DI的阶段,故此处调用缓存中的BeanFactory的目标方法getObject,返回的不应该是一个完整实例,而是一个earlyBeanReference;

此处,大家只需对每个bean 都有BeanFactory这件事有个概念,还有就是 三级缓存中缓存的是工厂而非实例这件事有个概念就可以了。

第三步:对Bean进行依赖注入

对Bean的DI由populateBean(beanName, mbd, instanceWrapper);方法完成

依赖注入是如何实现的呢?下面给出流程图。

第四步:依次调用BeanPostProcessor的实现类的目标方法(生成AOP代理对象的时机)

在面经中讲spring的生命周期会提到在创建Bean实例时候,会有BeanPostProcessor的前置方法,Bean的init方法,BeanPostProcessor的后置方法调用,它的调用时机就是在DI完成以后,由 initializeBean(beanName, exposedObject, mbd);方法进行处理。

具体分以下三个步骤:

 

第一步,调用所有BeanPostProcessor实现类的前置方法。

第二步,调用目标类的init方法

第三步,调用所有BeanPostProcessor实现类的后置方法。

其中,我们所熟悉的AOP代理,就发生在第三个步骤,至于为什么不在第一步进行代理呢?AOP代理分为,动态代理和CGLIB代理两种,如果配置的是动态代理的话,产生的代理对象是接口类型的,而非实现类类型的, 而init方法存在于实现类中,接口中不一定有,在这种情况下调用第二步的init方法就会报错。

使用注解的话,进行AOP代理的类是AnnotationAwareAspectJAutoProxyCreator。它的继承关系如下图:

 

 

此处大家只要知道代理对象的处理流程会在DI之后就可以了。

第五步、存入单例池

最后一步 :addSingleton(beanName, singletonObject);  beanName为该Bean的ID,singletonObject为该bean DI后的实例,调用addSingleton()就是将这个添加到一级缓存单例池中。这时候,就可以被其他的Bean依赖注入的时候所引用了。
普通Bean创建流程至此结束。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值