SpringBean生命周期解析
一、前言
Spring的主要功能之一就是实现Bean的管理,主要用于管理通过XML文件(如<bean>标签)、注解(@Bean)和用户程序动态注入的Bean。这些Bean在Spring容器中都是以BeanDefinition的形式存在,而BeanDefinintion包含了以下Bean的关键信息:
- Bean的类信息:Bean对应的java类,如Xml配置中的<bean>标签中的class属性,或者带有@Bean注解的类。
- Bean的名称:Bean在Spring容器中的唯一名称,如Xml配置中的<bean>标签中的id和name属性,或者@Bean注解中的value属性。一个Bean可以有多个名称,当bean没有指定名称,会生成按照类名生成对应的驼峰命名,生成方法参考JavaBean内省的方法:java.beans.Introspector.decapitalize。
- Bean的作用域:同一个Bean的作用范围,如单例模型在Spring容器中只会实例化一次。
-构造函数参数:用依赖注入的方式注入参数。适用于依赖的Bean不可以为null的情况。 - Bean的属性:如@Autowired的字段等,适用于依赖的Bean可以为null的情况。
- 依赖注入的方式:如按名称注入、按类型注入、ref方式注入、构造函数参数注入等。
- 懒加载属性:懒加载属性用于设置一个类的加载时机,如果为True,表示容器启动时并不会加载这个Bean,而是在需要的时候再加载这个Bean,可以通过<bean>标签中的lazy-init="true"设置。
- 初始化方法:Bean初始化完成之后的回调方法,可以通过<bean>标签中的init-method属性、定义一个InitializingBean和@PostConstruct注解来指定类初始化时候需要调用的方法。
- 销毁方法:Bean销毁之前用于释放资源的回调方法,可以通过过<bean>标签中的destroy-method属性、实现DisposableBean接口和@PreDestroy注解来指定类销毁之前需要调用的方法。
二、Bean的作用域(Scope)
2.1 什么是Bean的作用域
直接说Spring Bean的作用域可能有点难懂,此处我们用java变量的作用域来类比介绍SpringBean的作用域:
如对于以下代码,变量q的作用域只在内层花括号代码块中可见,而x则在外层花括号的代码块中可见,所以x和q具有不同的作用域。
{
int x = 12;
/* only x available */
{
int q = 96;
/* both x & q available */
}
/* only x available */
/* q “out of scope” */
}
那么Spring Bean的作用域和java变量的作用域有什么不同呢?我们用Spring Session Scope作用域的Bean举例说明,下图中假设UserDao的作用域是Session级别
- SessionA的Request1请求中需要获取UserDao的Bean,由于容器中现在不存在UserDao的实例,就新建一个实例UserDao1的实例,
- SessionA的Request2请求需要获取UserDao的Bean,Request1和Request2都在SessionA中,所以Request2也可以看到UserDao1,所以直接使用已经创建好的UserDao1。
- SessionA的Request3和Request2相同,直接使用UserDao1.
- SessionB的Request1到来时,也需要获取UserDao的Bean,由于UserDao1不在SessionB中创建的,所以此时看不到UserDao1,SessionB的Request1只能新实例化一个Bean UserDao2.