写在最前
从十一到现在两周,IOC部分源码读了一半多,是力气活,也是个精细活。全部写出来心有余力不足,所以找些重点写写。
简述 bean 实例化之前
Spring中不是启动容器时就开启bean的实例化进程,它首先会对资源进行读取并对bean进行初始化。
Spring将资源的定义和资源的加载区分开,Resource
定义了统一的资源,默认实现是AbstractResource
,资源的加载由ResourceLoader
接口的不同实现类返回Resource。紧接着,解析Resource
资源,将用户定义的Bean装载成BeanDefinition
,每一个Bean对象都对应着一个BeanDefinition
。BeanDefinition
存在于IOC内部容器中的HashMap结构。再紧跟着,向IOC容器注册解析好的BeanDefinition
,这个过程是通过BeanDefinitionRegistry接口来实现的。
初始化之后,会进行真正bean的加载,因为BeanDefinition
不是想要的bean。初始化默认为懒加载,第一次调用getBean()
时进行初始化。
首先得到可使用正确的beanName,这是涉及到别名或者factoryBean 。bean的作用域有singleton,prototype 和其他,Spring先尝试从缓存中加载单例bean,否则开始创建bean的实例。创建bean的实例可以理解为将BeanDefinition
转换为BeanWrapper
,BeanWarpper提供了get、set方法。之后还有一系列处理:MergedBeanDefinitionPostProcessor 属性合并,单例模式的循环依赖处理,属性填充,初始化bean。
在初始化bean这个过程中的代码,就包含了对XXXAware接口的处理,后置处理器,以及自定义的init-method方法。
Bean生命周期
回到最开始,看一下spring bean 的生命周期:
-
实例化Bean
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。
对于ApplicationContext容器,当容器启动结束后,便实例化所有的bean。
容器通过获取BeanDefination对象中的信息进行实例化。并且这一步仅仅是简单的实例化,并未进行依赖注入。
实例化对象被包装在BeanWrapper对象中,BeanWrapper提供了设置对象属性的接口,从而避免了使用反射机制设置属性。
在实例化bean的过程中,Spring采用策略模式决定采用反射还是 CGLIB 动态字节码。Spring 默认采用 CglibSubclassingInstantiationStrategy实例化bean,他既可以以反射实例化对象,还可以通过 CGLIB 的动态字节码的方式,以方法(setXxx)的方式注入对象实例化。
-
设置对象属性(依赖注入)
实例化后的对象被封装在BeanWrapper对象中,并且此时对象仍然是一个原生的状态,并没有进行依赖注入。
紧接着,Spring根据BeanDefinition中的信息进行依赖注入。
并且通过BeanWrapper提供的设置属性的接口完成依赖注入。
-
注入Aware接口
紧接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给bean。
private void invokeAwareMethods(final String beanName, final Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { ClassLoader bcl = getBeanClassLoader(); if (bcl != null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); } } if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this