生命周期
平时我们只会将Bean正确的装配到Ioc容器中, 但是并没有关心Ioc容器如何装配和销毁Bean的过程, 有时候我们也需要自定义初始化或者销毁Bean的过程, 以满足一些Bean 特殊初始化和销毁的要求, 例如我们希望数据源在其关闭的时候调用其close方法, 以释放数据库的连接资源, 这是在项目使用过程中很常见的要求. 为了解决这些问题, 我们有必要了解Spring IoC初始化和销毁Bean的过程, 这便是Bean的生命周期的过程, 它大致分为Bean定义, Bean的初始化, Bean的生存期和Bean的销毁4个部分, 其中Bean定义过程大致如下:
- Spring通过我们的配置, 如@ComponentScan定义的扫描路径去找到带有@Component的类, 这个过程就是一个资源定位的过程.
- 一旦找到了资源, 那么它就开始解析, 并且将定义的信息保存起来. 注意, 此时还没有初始化Bean, 也就没有Bean的实例,它有的仅仅是Bean的定义。
- 然后就会把Bean定义发布到Spring IoC容器中. 此时, IoC容器也只有Bean的定义,还是没有Bean的实例生成。
完成了以上的3步, 只是一个资源定位并将Bean的定义发布到IoC容器的过程, 还没有Bean实例的生成, 更没有完成依赖注入. 在默认的情况下, Spring会继续去完成Bean的实例化和依赖注入, 这样从Ioc容器中就可以得到一个依赖注入完成的Bean. 但是, 有些Bean会受到变化因素的影响, 这时我们倒希望是取出Bean的时候完成初始化和依赖注入, 换句话说就是让那些Bean只是将定义发布到IoC容器而不做实例化和依赖注入, 当我们取出来的时候才做初始化和依赖注入等操作(@ComponentScan注解中的属性lazyInit)
注解@ComponentScan中还有一个配置项lazyInit, 只可以配置Boolean值, 且默认值为false, 也就是默认不进行延迟初始化,因此在默认的情况下Spring会对Bean进行实例化和依赖注入对应的属性值. 如果配置为true, 则不会在发布Bean定义后对Bean立马进行实例化和依赖注入, 而是在需要用到此Bean(获取Bean)的时候才去实例化和依赖注入
如果仅仅是实例化和依赖注入还是比较简单的, ,还不能完成进行自定义的要求, 因为这都是Ioc容器在做的事情, 为了完成依赖注入的功能, Spring在完成依赖注入之后, 还提供了一系列的接口和配置来完成Bean初始化的过程. Spring在完成依赖注入后, 还会进行如下图的流程来完成它的声明周期, 下图描述的是整个Ioc容器初始化Bean的流程, 作为开发者, 需要注意这些流程, 除此之外, 还需要注意一下两点:
- 这些接口和方法是针对什么而言的, 对于下图的流程中, 在没有注释的情况下的流程节点都是针对单个Bean而言的,但是BeanPostProcessor是针对所有Bean而言的, 这是我们需要注意的地方
- 即使你定义了ApplicationContextAware接口, 但是有时候并不会调用, 这要根据你的IoC容器来决定. 我们知道Spring IoC容器最低的要求是实现BeanFactory接口, 而不是实现ApplicationContext接口. 对于那些没有实现ApplicationContext接口的容器, 在生命周期对应的ApplicationContextAware定义的方法也是不会被调用的, 只有实现了ApplicationContext接口的容器, 才会在生命周期调用ApplicationContextAware所定义的setApplicationContext方法。