共计 3772 个字符,预计需要花费 10 分钟才能阅读完成。
Bean Scopes,Spring Bean 的作用域,也就是 Spring 创立的 Bean 实例的失效范畴。
Spring 提供了如下 6 中不同的作用域:
- singleton: 单例 Bean,每一个 Spring IoC 容器中只有一个 Bean 实例,这是 Bean 的默认作用域。
- prototype:原型 Bean,每申请一次就生成一个新的 Bean 实例
- request:仅对 web-aware Spring ApplicationContext 失效,每一次 HTTP 申请生成一个 Bean 实例。
- session:仅对 web-aware Spring ApplicationContext 失效,每一个 HTTP session 对应一个 Bean 实例。
- application:仅对 web-aware Spring ApplicationContext 失效,ServletContext 生命周期对应一个 Bean 实例。
- websocket:仅对 web-aware Spring ApplicationContext 失效,websocket 申请对应一个 Bean 实例。
其中有 4 个是和 web-aware Spring ApplicationContext 相干的,也就是和 web 利用相干,最罕用的是 singleton 和 prototype 两种。
单例 Bean
singleton,单例 Bean,是 Spring 默认的 Bean 作用域,咱们在配置 Bean 的时候如果没有指定作用域,那么他的作用域就是 singleton。
Spring 官网的一张图高深莫测的讲清楚了单例 Bean 的含意:
定义了一个 id 为 accountDao 的 Bean,被其余 3 个 Bean 援用。如图,咱们在定义 accountDao 的时候没有指定作用域,默认的,他的作用域就是 singleton,单例 Bean。那么,在整个 Spring IoC 容器中就只创立一个 accountDao 的 Bean 实例,3 个援用类援用的其实是同一个 accountDao 实例。
这种状况系按咱们肯定要留神 accountDao 的线程平安问题!应用单例 Bean 的时候你肯定要留神线程平安问题,尽可能的防止在单例 Bean 中应用属性对象,或者你十分明确的晓得该属性不须要关注线程安全性!
接下来思考一个问题: 定义为单例 Bena 就肯定示意整个 Spring IoC 容器中只有该类的一个对象吗?
答案显示是 No,你当然能够在 Spring IoC 容器中为某一个类创立多个单例对象。
原型 Bean
原型 Bean 指的是 Spring IoC 容器中会有多个 Bena 实例,利用没申请一次,Spring IoC 容器就会生成一个新的 Bean 实例返回。
如图,accountDao 定义为原型 Bean,被其余 3 个 Bean 援用,不论其余 3 个 Bean 是单例还是原型 Bean,Spring IoC 注入的 accountDao 都会是 3 个不同的对象。
原型 Bean 在申明的时候须要显式指定 scope:
<bean id="dependencyB" class="springTest.DependencyB" scope="prototype">
</bean>
也通过注解形式指定 scope:
@Component
@Scope("prototype")
public class DependencyB implements IDependencyB{
@Autowired
//@Qualifier(value="dependencyA3")
private IDependencyA dependencyA;
public static void main(String[] args) {System.out.println("I am a new comer...hello world");
}
@Override
public void testB(){System.out.print("This is DependencyB's test and ...");
dependencyA.test();}
启动类加测试代码:
public class App {public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfiguration.class);
System.out.println("Now start to getbean...");
DependencyB dependencyB = applicationContext.getBean(DependencyB.class);
dependencyB.testB();
System.out.println(dependencyB);
dependencyB=applicationContext.getBean(DependencyB.class);
System.out.println(dependencyB);
}
}
执行启动类:
Now start to getbean...
This is DependencyB's test and ...I am DependencyA test...
springTest.DependencyB@53ca01a2
springTest.DependencyB@358c99f5
能够看到两次获取 DependencyB,失去的是不同的对象。
原型 Bean 的非凡之处还在于:创立的时候交给了 Spring IoC,然而 Spring IoC 并不负责销毁。然而好消息是,因为原型 Bean 的特殊性,所以,Spring IoC 容器也没有必要在每次创立之后缓存该实例,Spring IoC 容器只须要 new 出一个对象(其实不是 New 的,是通过反射机制或者 CGLIB 创立的)间接返回给利用就 OK,所以,也就不会导致内存透露,
单例 Bena 和原型 Bean 的依赖
如果一个原型 Bean 要依赖一个单例 Bena,其实是没有任何问题的,因为依赖注入是产生在 Bean 实例化之后的属性赋值阶段,原型 Bean 在每次申请的时候都会进行一次属性赋值、都会执行一次依赖注入,单例 Bean depencyA 会注入到原型 Bean dependencyB 中,不会存在任何问题。
其实咱们下面的例子,原型 Bean dependencyB 就是依赖单例 Bean dependencyA 的,咱们把 DependencyB 的 test 办法稍加革新、打印一下依赖对象 dependencyA:
@Override
public void testB(){System.out.print("This is DependencyB's test and ..."+dependencyA);
dependencyA.test();}
执行启动类:
Now start to getbean...
This is DependencyB's test and ...springTest.DependencyA@53ca01a2I am DependencyA test...
springTest.DependencyB@358c99f5
This is DependencyB's test and ...springTest.DependencyA@53ca01a2I am DependencyA test...
springTest.DependencyB@3ee0fea4
咱们会发现两次获取到的尽管是不同的 dependencyB 对象,然而他们的依赖对象 dependencyA 却是雷同的对象,因为 dependencyA 是单例 Bean。
然而反过来就不是这么回事了:如果一个单例 Bean 依赖一个原型 Bean 会怎么样?
为此,咱们把上例中的 DependencyB 批改为单例 Bean,把 DependencyA 批改为原型 Bean,做一下测试。
只须要把 @Scope(“prototype”) 注解从 DependencyB 类转移到 DependencyA 上即可。
运行启动类:
Now start to getbean...
This is DependencyB's test and ...springTest.DependencyA@53ca01a2I am DependencyA test...
springTest.DependencyB@358c99f5
This is DependencyB's test and ...springTest.DependencyA@53ca01a2I am DependencyA test...
springTest.DependencyB@358c99f5
咱们发现尽管定义 DependencyA 为原型 Bean,然而两次获取到的 DependencyB 的依赖对象 DependencyA 是同一个对象。
这也不难理解,Bena 的注入是在 Bean 实例化之后的属性赋值阶段解决的,单例 Bean 只实例化一次、属性负责也只产生一次,所以,依赖对象也只能被注入一次,尽管属性是原型 Bean,因为只能被注入一次所以也就只能是同一个对象了。
其实倡议最好不要在单例 Bean 中援用原型 Bean,如果非要这么做的话,Spring 也提供了一种解决办法:Method Injection,能够采纳 xml 配置或注解 @Lookup 实现,个人感觉利用很少,临时疏忽。
上一篇 Spring FrameWork 从入门到 NB – 主动拆卸