文章目录
在spring中,哪些构成应用程序的主体以及被Spring IOC容器托管的对象叫做Bean
Bean的作用域概述
在Spring中,Bean默认都是单例的
在Java中,单例是基于JVM的,每个JVM中只有一个实例。
而Spring中的单例是基于BeanFactory的,也就是Spring IOC容器,Spring IOC的底层实质是一个工厂模式
Bean有五种作用域,其中三种仅在基于Web的应用中使用(无论使用的Web框架是什么),只能用在基于Web的SpringApplicationContext环境
下面简单的介绍一下五种作用域
类别 | 简介 |
---|---|
singleton | 在Spring IOC容器中仅存在一个Bean实例,Bean以单例方式存在,也是默认作用域 |
prototype | 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,都相当于执行new XXX() |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 |
session | 同一个Http Session共享一个Bean,不同Session使用不同Bean,仅适用于WebApplicationContext |
globalSession | 一般用于Portlet应用环境,该作用域仅适用于WebApplicationContext环境 |
格式(以singleton为例)
xml格式
<bean class="com.dean.controller" id="userController" scope="singleton"></bean>
注释格式
@Componet("userController")
@Scope(value="singleton")
//加在Controller类上
详细说说
Singleton
- 当一个Bean的作用域为Singleton,那么Spring IOC容器中只会存在一个共享的bean实例,并且当所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例
- Singleton是单例类型,即创建容器时就同时自动创建了一个Bean对象,不论是否被使用,它都已经存在了,每次获取到的对象也都是同一对象。
- 可以对非线程安全的对象采用单实例模式
- 虽然启动时,自动实例化bean会花费一些时间,但它却带来了两个好处:
对bean提前的实例化操作,会及早发现一些潜在的配置问题
Bean以缓存的方式运行,当运行到需要使用该bean的时候,就不需要再去实例化了,加快了运行效率
Prototype
- 一个Bean定义对应多个对象实例
- Prototype的作用域会导致在每次对该bean请求时,都会创建一个新的Bean实例,
- 在创建容器时并没有实例化,当我们去获取Bean实例的时候才会去创建一个对象,而且每次获取到的对象都不是同一个对象
- 有一点非常重要,Spring不能对一个prototype bean的整个生命周期负责:容器在初始化、装配或装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了
- 清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责
Request
- 在一次HTTP请求中,一个Bean定义对应一个实例
- 每个Http请求都会有各自的bean实例
- 针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,该LoginAction bean实例仅在当前Http request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction bean定义所创建的实例,将不会看到这些特定于某个请求的状态变化
Session
- 在一个Http Session中,一个Bean定义对应一个实例,作用域仅在Web的Spring ApplicationContext情形下有效
- 针对某个Http Session,Spring容器会根据userPerferences bean定义创建一个全新的userPerferences bean实例,且该userPerferences bean仅在当前Http Session内有效
- 根据需要放心的更改所创建实例的内部状态,而别的Http Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化
Global Session
- 在一个全局Http Session中,一个bean定义对应一个实例。
- 仅在基于portlet的web应用中才有意义Portlet规范定义了全局Session的概念
生命周期
以下图来自网络(图方便理解以下文字)
Bean实例化过程
- Spring对bean进行实例化,默认bean的作用域是单例
- Spring对bean进行依赖注入
- 如果bean实现了BeanNameAware接口,Spring将bean的id传给setBeanName()方法
- 如果bean实现了BeanFactoryAware接口,Spring调用setBeanFactory方法,将BeanFactory实例传进来
- 如果bean实现了ApplicationContextAware接口,它的setApplicationContext()方法将被调用,将应用上下文的引用传入到bean中
- 如果bean实现了BeanPostProcessor接口,它的postProcessBeforeInitialization方法将被调用
- 如果bean实现了InitializingBean接口,spring将调用它的afterPropertiesSet接口方法,类似的如果bean使用了init-method属性声明了初始化方法,该方法也会调用
- 如果bean实现BeanPostProcessor接口,它的postProcessAfterInitialization接口方法将被调用
- 此时bean以及准备就绪,可以被应用程序使用,他们将一直驻留在应用上下文中,直到该应用上下文被销毁
- 若bean实现了DisposableBean接口,spring将调用它的distroy()接口方法。同样的,如果bean使用了destroy-method属性声明了销毁方法,则该方法被调用
- 实际上:很多时候并不会去实现上面所描述的哪些接口
Bean生命周期
- init-method 指定一个方法,在实例化bean时,立即调用该方法
- destroy-method 指定一个方法,只有从容器中移除bean之后,才能调用该方法
- default-init-method和default-destory-method 在你有太多同名初始化和销毁方法的bean时,不需要在每一个bean上声明初始化和销毁方法,而是用上述两个设置默认值