此处介绍的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创建流程至此结束。