一个spring bean被实例化时经历了什么?
普通的对象被实例化无非就是被编译成.class文件,当jvm对其运行时开辟内存调用new形成一个实例;
而如果是被springbean对象,在spring运行时,会把类的信息放在BeanDefinition类中,为的就是可以原本的类型对其做出修改判断,包括isLazy、isAbstract、dependsOn等等的判断,根据这个类的各种set方法储存,当扫描到一个符合规则的类后就会实例化BeanDefinition,然后根据类名生成一个名字,再将名字作为key,BeanDefinition作为value,存到一个map中,这个map其实也是放在我们经常说的bean工厂中,然后开始对这个map进行遍历实例化然后放到容器(如:AnnotationConfigApplicationContext,这只是其中一种容器,spring的bean工厂有多种类型,创造出来的容器也可以是多种的)中,这样我们就可以通过容器去调用已经实例好了的springbean对象;
从上面的流程中,我们不难发现,其实springbean被实例化之前依据的不是一开始所被扫到的类信息,而是最后存到放到map里的类信息和状态,spring有自己默认的接口对map进行实例化过程,同时对外也留了个接口BeanFactoryPostProcessor给我们程序员可以做自己的修改.
写完之后,发现自己被自己绕晕了,所以,通过源码,更加直观地感受下会好点(这里以AnnotationConfigApplicationContext为例):
首先,我们开启spring,第一行代码拿到的就是一个容器:
我们打开AnnotationConfigApplicationContext类:
发现第一步运行的是this(),也就是本身的构造类,点开看:
这里我在源码做了简单的标注,至于怎么去解析,怎么去扫描等我学完一个大概了流程后再去细看,需要注意的是,这个类其实是有父类的,
也就是我们也要去看父类里的构造参数做了什么:
这里的beanFactory就是我们一直所说的bean工厂了,而这个bean工厂是DefaultListableL类型的,实现的原始接口就是BeanFactory,也就是我上面说的不同类型的bean工厂会产出不同类型的容器;
至此,我们完成了构造函数里this();这行代码了
通过断点调试,我们可以知道其实到这一步,也就是执行register(componentClasses);之前,我们其实是并没有将我们自己写的类加载到map中,也就是之前没细说的scan步骤其实只扫描了spring内置的5大原始类;
接下来:register(componentClasses),源码:
这里其实是将我们配置类的BeanDefinition并放到map中,这样我们就可以调用配置类里@Bean的方法了;
最后的:refresh();才是实例化我们springbean的所在方法;
首先,要扫描到并将对应的BeanDefinition类放到map中,而这一步对应的就是refresh方法里的:
且我们之前自己所扩展的BeanFactoryPostProcessor接口也会在这里被调用,但是到这一步,springBean还没被实例化,除了我们自己扩展的继承BeanFactoryPostProcessor类已经实例化了,其余的只是放到map中了,最后才通过这一步对map中所有的springbean进行实例化的:
也正是这一步实例化,会体现BeanDefinition类的作用,首先会验证是不是抽象、是不是单例、是不是懒加载等等的判断,然后得到类--BeanDefnition get class;再根据类来推断构造方法;然后再暴露一个工厂,再进行属性注入,再调用aware接口,再调用生命周期的初始化回调方法;完成AOP,如果是单例再put 到map中,最后进行销毁;(这里的详细实例化过程我会结合源码在下节博客中写出)
至此,我们配置类配置好的包里有所标注的类就都实例化好放到一个容器中了,当然,上面过程只是bean实例化放到容器中最外部最表象的流程,里面所涉及的详细流程我会在以后中边学边记.......待续!