今天我们来根据Spring循环依赖来由浅入深的研究Spring的源码,扯到循环依赖就是属性的注入,所谓的自动注入
说到自动注入就会懂Spring bean的生命周期,那么提前要熟悉Spring bean的实例化过程
我们想到一个面试都会问到的问题
Spring当中循环依赖怎么解决
Spring中默认单例支持循环依赖
Spring依赖注入是在什么时候完成的
Spring初始化过程完成的
依赖注入的功能-------------->在初始化时候完成
- 初始化bean bean有一个初始化过程 1,2,3,4,5,6,7,N
Spring Bean的生命周期在哪一步完成的依赖注入
现在我们来理清bean 和 Java对象的区别
Spring bean是经历完整生命周期的
java对象就是new出来的,没有交给Spring容器进行管理
bean一定是java对象,java对象不一定是bean
如果了解Spring bean的生命周期肯定要知道Spring bean的产生过程--------------->
bean是由什么产生的
Class--------------------->beanDefnition------------------------>object(bean)
普通类的实例化过程,通过user.java通过javac编译成class文件,会调用main方法然后调用c++的代码启动jvm虚拟机,当你一旦启动jvm虚拟机的时候,jvm虚拟机就会在磁盘上把你刚刚编译好的class文件加载到jvm内存中比如方法区,当遇到new关键字的时候它就会根据方法区提供的java模板去堆上分配一块内存用来存储这个对象
Spring Bean实例化过程,比如说X类,我加了@service或者@Compent注解,Y没有加,一旦允许jvm虚拟机,也就是main方法运行起来,jvm虚拟机会把这个类的class文件加载到虚拟机中,一旦遇到Spring容器初始化的代码,Spring容器会在这个代码里面做很多事情,它会解析我们提供的AppConfig这个类的@ComponentScan("com.ioc.groups")扫描这个包路径,通过这个包路径拿到里面所有的类,比如说拿到X类,按照思路拿到X类是不是把这个Xnew出来放到Spring容器中,但是Spring没有这么做,为什么,因为拿到这个类的时候不知道要不要new,为什么不要new,因为有可能这个X是个原型对象也就是scope=prototype,还有可能这个X需要懒加载Lazy表示这个类初始化的时候不需要new,要等到用的时候才会new,Spring有个注入模型,不知道是用byName还是ByType注入,它需要解析,Spring扫描出拿到这些类第一步并不是new,而是把这些类的元信息,配置信息,它要得到这些信息,得到这些信息后怎么办呢,Spring就会用一个对象来存储这些信息,这个对象叫BeanDefnition的子类,BeanDefnition是一个接口,这个接口有很多实现类,我们叫BeanDefnition的子类,这个子类有很多属性,这个属性用来存储X的所有信息,比如Spring把X类扫描出来,然后把X拆分信息放到这个对象里面再把这个对象放到map中,Spring可能扫描的对象不止一个,所有可能会进行多次解析,解析完之后,这个map会有多个BeanDefnition对象,注意是BeanDefnition子类对象,Spring的强大的地方是Spring提供了很多扩展点供开发者扩展,如果不去扩展,放到map之后Spring会去调用一个方法PrcInstantiatcSingletons,从这个map中遍历BeanDefnition的所有信息,它都可以拿到,拿到拿到之后如果验证成功把对象new出来,new出来之后放到单例池中,这个Spring单例池也是一个map,这里就是单例对象了,注意如果是原型对象(scope=prototype)不是在Spring初始化的时候new这个对象而是在用到这个对象的时候在getBean的时候new这个对象,这是单例对象大概的实例化过程
如果你能够对Spring进行扩展,前面步骤一样的,把X扫描出来,把X进行拆分验证解析,解析出来,放到map中,这个时候如果一个java程序员对Spring进行了扩展,那么怎么对Spring进行了扩展呢,只需要提供一个接口就可以了,只需要实现一个接口,比如说有一个类实现了一个接口,实现了一个BeanFactoryPostProcessor,Spring把对象存在map之后,new对象之前,Spring会看一下程序员有没有对我进行扩展,如果进行了扩展,Spring就会调用扩展的一些方法,实现接口会实现里面的方法,调用方法的时候会把map传过来,程序员拿到这个map之后,这里面不是拿到一个X吗,存的一个BeanDefnition对象,这个BeanDefnition对象里面有个属性叫bean Class,这个bean class里面存的就是X的类,这个时候拿到这个map之后,可以把这个X改成Y,这个Y实际上并没有扫描的,等改完之后重新放回去,放回去之后Spring认为你扩展完了,它会继续来new,这时候new出来的会是Y而不是X,这个map的key是类名
把以上Spring bean实例化原理搞懂才能更好的阅读Spring的源码