◆Spring在Bean实例的创建过程中做了 很多精细化控制
finishBeanFactoryInitialization(beanFactory);
// Instantiate all remaining (non-lazy-init) singletons.beanFactory.preInstantiateSingletons();
finishBeanFactoryInitialization(beanFactory);方法里面的preInstantiateSingletons()会去初始化那些非延时加载的bean实例。
而ApplicationConCtext容器默认管理的bean都是非延迟的单例,所以如果没有特别的设置,bean都会在这里被调用getBean方法去实例化。
AbstractAutowiredCapableBeanFactory:自动装配的服务
AbstractBeanFactory: 抽象类,里面提供一个获取bean实例的方法doGetBean,根据不同的scope进行不同的处理
DefaultSingletonRegistry: 单例bean默认的实现类,里面是bean而不是beanDefinition,里面有一个方法会尝试从三级缓存里获得bean实例,(三级缓存是为了解决循环依赖的问题,循环依赖:类A里面套类B,类B又有A的情况)
如果缓存里没有bean实例,那么容器就会创建出来,因此就会来到AbstractAutowiredCapableBeanFactory,在doCreateBean方法里面光创建Bean实例是不够的,还需要看看实例的属性有没有被@Autowired或者@Value标记。
applyMergeBeanDefinitionPostProcessors: 对合并后的BeanDifination做后置处理
populateBean: 考虑被标记之后,对属性进行依赖注入
AutowiredAnnotationBeanPostProcessor: 做属性的后置处理,再来到DefaultListableBeanFactory这里去解析依赖关系(因为BeanDefinition都保存在这里),找到bean之间的依赖关系之后使用DependencyDescriptor里面的injectionPoint进行注入
1、单例Bean有可能是bean实例(直接返回),或者是FactoryBean实例本身(当调用getObject方法去返回bean实例),获取不到就让容器去创建bean
什么是循环依赖?
3、如果该容器中没有注册该beandefinition的实例,则递归去父容器获取Bean实例。
5、所谓的显式就是给bean设置deoends-on这个属性。
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
//**从缓存中获取bean实例**
从缓存中获取bean实例
完备的bean实例会被保存在一级缓存singletonObjects,不完备的bean实例被保存在二级缓存earlySingletonObjects或者三级缓存singletonFactories里,并且实例只能存在于三层中的某一层。
为什么没有注入属性的bean还呢个让其返回呢?
为了解决循环依赖的问题,打破鸡生蛋,蛋生鸡的无限轮回。
isSingletonCurrentlyInCreation();//存放当前正在创建的bean的名字列表
isSynthetic:表示某个类是由自己机制生成的类,
bean.isSynthetic():表示该bean是spring容器内部生成的bean实例,不允许第三方或者用户去改动。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);//如果是普通的bean直接返回,如果是FactoryBean,则返回它的getObject
为什么我们都可以通过 getSingleton(beanName); 获得实例了,为什么还要有getObjectForBeanInstance?
原因是看看bean是否是FactoryBean,如果是还需要调用它的getObject()方法去返回实例。
spring为什么不显式指定依赖?
因为既然你显示指定了依赖,就表明某bean一定是在另一个bean之前创建,depends-on主要是用来控制顺序的。如果产生了循环依赖,spring也不知道用户究竟先要那个bean先创建出来。
dependentBeanMap:我所依赖的那些bean的名字的那些列表
UserInfo类里面有一个Human类的成员变量,则userInfo是依赖human的,所以human就作为dependentBeanMap里面的key,userInfo则为dependentBeanMap值的里面的其中一个元素。
dependenciesForBeanMap:依赖以我的bean的名字的列表
另外一边dependenciesForBeanMap关系和上面就是反过来的。它的key存储的是userInfo,human作为值的其中的一个元素存储里面。
两个getSingleton方法。第一个:尝试从三级缓存里获取需要创建的bean实例。
另外一个调用getObject方法最终调用createBean的方法去真正创建出bean实例来。
只有单例是支持循环依赖的
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactoryimplements AutowireCapableBeanFactory {
里面的createBean方法
@Override
public Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {// Use non-singleton bean definition, to avoid registering bean as dependent bean.RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);return createBean(beanClass.getName(), bd, null);
}
主要去了解单例的@Autowired的依赖注入
主要解析bean对应的class对象
之前往容器里创建了BeanDefinition实例,创建bean之前会取出BeanDefinition实例,之后依据BeanDefinition的属性创建出bean实例来。
RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
为什么使用RootBeanDefinition接收BeanDefinition实例?
因为有的bean有parent属性,将child和parent属性合并后归并到chile里面,而如果是普通的bean,RootBeanDefinition也可以接收。
提前暴露:bean是单例并且支持循环依赖的同时还满足正在创建的条件。满足上面三个条件就允许将创建出来的但是还没有赋值上属性的bean给暴露在外供外部使用。
Suppier接口里面的通过get方法返回设置上的bean实例,该接口用来暂存实例,以供匿名调用。
覆盖方法
public void prepareMethodOverrides() throws BeanDefinitionValidationException {// Check that lookup methods exist and determine their overloaded status.if (hasMethodOverrides()) {getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);}
}
主要就是通过beanDefinition实例加载class对象,获取到class对象之后再看看BeanDifinition里面是否配置了replace-method或者lookup属性,进而检查一下是否有相关覆盖的方法,并做相关的标记。随后就回去判断是否要对bean进行包装处理,如果没有就调用doCreateBean方法进行spring容器对bean的创建。
首先会通过实现配置好的工厂方法、含参构造器注入、无参构造器注入创建没有属性值的bean实例。之后执行BeanDefinition的后置处理器来处理BeanDefinition的属性,其中就包含了被@Autowired和@Value标记的属性,先将被这些标签标记的属性给记录下来,放到一个类里面,便于后序的依赖注入处理。之后会看看是否允许早期暴露(Bean是单例并且是支持循环依赖的同时还满足正在创建的条件)。之后填充Bean属性例如@Autowired属性就是在这注入的,之后对bean进行初始化操作,包括通过责任链模式用BeanPostProcessor去处理bean,对bean做最后的包装。初始化之后就会视情况给创建好的bean实例注册bean销毁时的相关逻辑,之后将创建好的bean返回给调用方调用。
调试代码断点处
getEarlyBeanReference
实际执行的地方:在AbstractBeanFactory的doGetBean方法里尝试获取缓存中的bean(即getSingleton方法)调用里面的getObject方法来执行bean实例的包装逻辑,
getBean方法被执行时会调用doGetBean方法,它先尝试从缓存中获取bean实例(getSingleton),如果缓存中没有,doGetBean方法会去调用createBean方法,在调用里面的doCreateBean方法进行创建bean实例。doCreateBean方法执行之后会将ObjectFactory这个实例给注册到三级缓存,在调用GetBean时就会来到缓存里去调用singletonFactory.getObject()(也就是getEarlyBeanReference开始执行)获取bean实例,再将实例存到二级缓存里,清空三级缓存实例,将完备的bean实例逐层返回。最后返回到doGetBean方法里,调用getSingleton方法(不同于上面那个)里的addSingleton,将返回的实例添加到一级缓存里,将完备bean二级、三级缓存给移除。
@Repository
public class GirlFriend {@Autowiredprivate BoyFriend boyFriend;
}
@Repository
public class BoyFriend {@Autowiredprivate GirlFriend girlFriend;
}
当初此创建A实例的时候,会调用addSingletonFactory将A实例添加到三级缓存里,随后调用populateBean给A实例赋值属性B实例,赋值时发现B实例不存在。因此去调用getBean方法去获取B实例,B实例也一样的,先将B实例添加到三级缓存里,在调用populateBean方法给B里面的属性A赋值,此时就会再次调用getBean()方法获取A实例,就可以从缓存中获得A实例给B注入上,完成了B的创建,随后将B的完备实例放入到一级缓存,并清空其他级缓存之后,将其完备实例返回给A,这样A也就完成了创建,后将A也放入一级缓存中,并清空其他级缓存,进而就完成了两个相互依赖的A、B单例的创建。
循环依赖的情况如下
◆构造器循环依赖( singleton、prototype(不支持循环依赖) )
◆Setter注入循环依赖( singleton、prototype )
构造器注入需要给构造器添加@Autowired标签
主函数里面:
容器在初始化的时候就加载了bean实例,为什么还要显示调用getBean方法?
refresh里面是初始化,容器只是在刷新完成之后提前加载非延时加载的单例,所以对于prototype来讲,需要显示调用进行首次加载。
发现直接抛异常,说明spring不支持prototype循环依赖的情况。
主函数
抛出异常
为什么spring不支持多例的循环依赖情况呢?
点进去getBean方法
当bean是prototype的并且显示在正在创建的bean的prototype列表当中,如果此处能够从缓存当中获得相关的内容,则表明getBean方法发生了递归,(因为prototypesCurrentlyInCreation是ThreadLocal的,如果同一个线程在执行时能在缓存中取得同样的bean,则表明getBean方法发生了递归,因为第一次执行是没有的,之后会像缓存中存储创建的bean的名字,再次执行到这里发现缓存是有值的,即是发生了递归的),那么如果在prototype正在创建的bean名字列表里找到该名字,则直接抛出异常
解决循环依赖的关键就是三级缓存,而三级缓存还解决了保证单例唯一性的问题。因为从缓存中取出来的实例是要保证bean是唯一的,所以三级缓存支持不了prototype。这也是prototype没有使用三级缓存而是简单的将bean的名字放到缓存当中的原因
主函数:
发现抛出异常
说明spring容器下singleton下只支持setter方式的循环注入
为什么单例的构造器方式不支持循环依赖呢?
单例的bean在首次创建时会来到doCreateBean方法里,对于setter的创建回去到addSingletonFactory的方法里面,先将创建出来的还未赋值的不完备的bean存放在三级缓存里,之后在调用populateBean方法递归调用给其属性赋值注入。而对于构造器来说就不会等到populateBean的时候才注入,而是在前面的createBeanInstance方法里创建出来的,此时还没有缓存,此时构造器的参数实例并没有被创建出来,即company里面的staff实例还没有被创建出来,则在这里又会尝试创建staff实例,而staff的构造函数有需要company实例,它没有被放入到缓存中,又会递归来到这里,造成无限循环,spring会提前把正在创建的单例的名字列表给缓存起来,以避免出现无限循环。
先前已经通过反射获得了一个bean,现在是往bean里面填充属性的时候。
◆调用Bean的Setter方法实例去给Bean设置上属性值
◆变量类型的转换,同时还要考虑处理集合类型的情况(在spring当中所有属性都是字符串,)
◆处理显式自动装配的逻辑( autowire = byName/byType )
第二步主要针对xml的情况,在变量上显式定义了( autowire = byName/byType )
通过容器的刷新获取非延时加载的bean的单单例的实例。
容器里面是否已经注册了自定义的InstantiationAwareBeanPostProcessor的bean处理器。如果有则通过责任链模式调用这些后置处理器的postProcessAfterInstantiation方法。
本章重点分析了spring依赖注入的脉络,以容器初始化的时候调用getBean()方法,创建非延时加载的bean单例为契入点,先是从AbstractBeanFactory的doGetBean开始
三级缓存:解决了循环依赖注入问题以及保证bean单例唯一性的问题
一级缓存保存了完备的带有属性值得bean实例,二级缓存没有给属性赋值得bean实例,三级缓存保存了用来包装实例得Object实例,
doGetBean方法的主要逻辑:
先从缓存中尝试获取Bean,没获取到再去判断循环依赖,之后递归去父容器获取Bean实例,此时如果容器没有配置父容器或者当前容器已经找到了对应BeanDefinition,那么就会从当前容器获取BeanDefinition实例,之后递归实例化显式(bean标签里被depends-on配置)依赖得Bean(一旦标签里配置了bean A depends-on B,那么就会将两者相互依赖的关系注册到容器里面,并且去实例化bean A所依赖得bean B),再根据不同得Scope策略创建Bean实例,我们主要研究得是Singleton,最后对Bean进行类型检查。
doCreateBean方法的主要逻辑:
如果是第一次创建Bean实例得话,最终会去调用createBean方法,为Bean实例得创建去做准备。随后调用doCreateBean方法进行真正的创建(主要针对的是setter方法注入的情况)
首先调用bean对应得参构造方法,创建出不带属性值得bean实例。针对注解来讲会调用applyMeragePostProccessor方法将被@Autowired或者@Value标记得方法和成员变量保存到injectionMeragedata实例中,并将injectionMeragedata实例保存到容器缓存里。随后判断容器中得bean是否允许提前暴露(即将没创建完备得bean实例给提前存入到缓存里以供递归方法通过getBean方法去获取,为了解决循环依赖的问题),之后调用populateBean方法对bean属性进行填充,之后对Bean进行初始化的处理,之后注册相关销毁逻辑,最后返回创建好的实例。
populateBean方法得逻辑
首先postProcessAfterInstantiation给用户提供绕开spring自行处理bean属性的口子,如果口子没有被使用再继续后续操作。先判断是否显示装配了自动配置,如果有则byType或者byName进行自动装配。如果没有自动装配标记则来到postProcessPropertyValues,对前面存到缓存得Bean对应得injectionMeragedata实例通过inject方法对被@@Autowired或者@Value标记得Bean属性进行处理。之后进行依赖检查校验,随后如果是xml方式且先前指定了byType或者byName进行自动装配,就会执行最后面的逻辑,来给bean的属性进行赋值,
Bean级别的后置处理器,作用:方便在调用getBean方法去创建Bean实例时,在特定的各个环节去触发这些后置处理器,以执行一些特定得逻辑,比如AOP的织入等等,以便对bean进行精细化的操作以及自定义的管理。