上文说到Spring bean初始化的原理,今天我们来彻底走到Spring源码来解读一下
Spring有一个BeanDefnition,而我们程序员可以修改它,怎么来扩展,我们开发者需要提供一个类实现一个叫BeanFactoryPostProcessor的接口

这个方法会传一个beanFactory回来,刚刚上篇说过在调用这个方法的回调的时候会把这个map传过来,这个map在这个工厂里面,这个工厂是什么,就是所谓的Spring的工厂,这个beanFactory工厂里面就包含这个map,拿到这个工厂后就会得到这个map信息,走入这个方法beanFactory.getBeanDefinition()

看到上图this.beanDefinitionMap.get(beanName);
就说明这个map存在工厂里面
我们调用这个工厂的API,这个工厂API底层实际上是调用map的API
BeanDefinition是个对象,所以我用BeanDefinition对象来接收它,只不过BeanDefinition是个接口是个父类,它的API不丰富,所以我们用子类来接收它,因为子类比父类更强大,上面有各种的API,因为接下来用到的API在父类中并没有
比如说setBeanClass这个API在父类中没有,在子类中被扩展了,所以尽量用子类
indexService.getBeanClass();毋庸置疑,获取的肯定是indexService,我们现在不拿,indexService.setBeanClass(userServcie);这时候整个map就改变了,改变之后为了让这个类生效,把这个类加一个注解@Component,一旦这个类生效,这个方法就会被调用,一旦这个方法被调用,改变了整个工厂bean的行为,那么改变行为的话,整个bean工厂就不存在indexService
我们来看一下源码

进入这个方法

然后进入这个实例化方法refresh
invokeBeanFactoryPostProcessors(beanFactory);这个方法是完成所谓的扫描,dubug调式一下可以看到spring容器中什么都不认识只有有一个AppConfig类认识,是因为这个类是手动给Spring的,然后往下走,当完成扫描后会有一个indexService
Spring什么时候开始初始化bean的
finishBeanFactoryInitialization(beanFactory);可以dubug调式一下当走完这个方法后,如果bean一旦实例化之后,这个构造方法就会打印,当走完这个方法后,构造方法打印了,证明这个方法是实例化bean,所谓的Sping bean的生命周期都在这个方法中,然后进入这个方法里调试一下就行了


beanFactory.preInstantiateSingletons();这个方法实例化单例,非lazy的对象
进入这个方法就会看到之前说到的list的作用

这个可以看到通过list拿到所有bean的名字
然后循环list从map中拿到所有的beanDefinition
Spring会验证是否是单例非lazy对象
当验证一切通过认为可以new会调用getBean方法进行实例化普通的bean
进入这个方法

然后看到调用doGetBean,进入这个方法

第一行代码是验证是否有非法字符串的,就是这个bean名字是否有非法字符串,一般没有非法字符串,验证完成之后它会把这个名字返回给你,然后它就可以拿bean
Object sharedInstance = getSingleton(beanName);这个方法背后的意义就是Spring从单例池中获取一遍,看看这个单例池中看这个bean有没有实例化

进入这个getSingleton方法可以看到调用这个getSingleton,进入这个方法

这个singletonObjects就是一个map,进入这个方法

可以看到英文注释大致意识是缓存我们的单例对象
说白了以前我们老师可能一直说的Spring容器,就是Spring单例bean初始化之后放到一个map中,就是这个singletonObjects,其实这样说不对,在Spring中有个专业的术语叫做单例的缓存池或者叫单例池
然后往下走

这个方法是判断这个类是不是在创建过程中
肯定不走这个方法,然后继续往下走
然后继续验证,当验证是否为单例,因为是单例所有走这个方法

这个会调用getSingleton方法会调用createBean创建bean,进入createBean这个方法
当进入这个createBean中还没有创建对象,因为刚才已经开始完成所有的验证,当验证完成之后Spring才开始创建对象,这也是我们所说的Spring生命周期的开始,其实前面说的扫描也是Spring bean的生命周期
然后我们进入这个createBean方法里,开始进行判断日志,然后把BeanDefinition
赋值给它
然后通过BeanDefinition对象获取bean的类型,我们通过BeanDefinition里面存的beanClass获取
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);我们可以通过BeanDefinition对象获取bean的类型,dubug可以看到resolvedClass
获取的是indexService因为这是一个class,这是一个BeanDefinition,我们通过BeanDefinition里面存的beanClass这个属性得到一个类,因为需要创建对象肯定要类,这是毋庸置疑的,当我们得到这个类后,判断这个beanClass有没有name之类的,这个先不管,都是验证的,继续往下走
怎么说明Spring是支持循环依赖的
Spring在生命周期的某个过程中,Spring在初始化Spring bean的过程中,当它把我们的 bean实例化之后,它会做一次判断当前这个容器允不允许循环依赖,怎么判断是根据一个属性的,allowCircularReferences
这个属性在Spring中默认是ture,这个属性可以通过Spring提供的API供我们修改为false,所以我们不修改Spring是默认开启循环依赖的
怎么关闭Spring的循环依赖
可以在refresh方法之前把allowCircularReferences设为false就可以关闭循环依赖
还有一种
beanFactory.setAllowCircularReferences(false);设置allowCircularReferences为false

其实这样写没有用
//初始化spring容器
AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext(AppConfig.class);因为这里已经初始化Spring容器了,已经支持了循环依赖了
怎么解决
如果你对Spring非常了解的话,还有一种写法
ac.regisater(AppConfig.class)把这个类传给ac.regisater方法
在手动调用一下ac.refresh();
为什么你这样做呢,可以进入AnnotationConfigApplicationContext
这个方法看一下

这个方法本质是调用默认构造方法,调用register,调用refresh
这个方法可以手动做了,首先调用默认的构造方法,然后调用register方法,然后调用refresh方法
refresh方法真正来初始化Spring环境最主要的代码
这样是不是可以在refresh方法之前把
AbstractAutowireCapableBeanFactory beanFactory =
(AbstractAutowireCapableBeanFactory) ac.getBeanFactory();
beanFactory.setAllowCircularReferences(false);这个方法写上

这样就可以关闭Spring的循环依赖
一共三种方法
1.修改源码
2.通过上述方法,在调用register之后在调用refresh设置allowCircularReferences为false
3.通过扩展Spring
为什么别人可以进阿里巴巴,是因为别人对Spring源码比较深入,这样都是有原因的,这些就是解决Spring循环依赖