上一篇 Spring Boot IoC(七)条件装配Bean
八、Bean的作用域
IoC容器最顶级的接口BeanFactory
中有两个方法isSingleton
(单例)和isPrototype
)(原型)
- isSingeleton:返回true,Bean在Ioc容器中以单例存在(Spring默认)
- isPrototype:返回true,每次获取Bean,Ioc容器都会创建一个新的Bean。
而在JAVA EE 的WEB容器中,还存在page
(页面),request
(请求),session
(会话)和application
(应用)4种作用域。其中page是针对JSP当前页面的作用域,Spring无法支持。
作用域关系如下表
作用域类型 | 使用范围 | 作用域描述 |
---|---|---|
singleton | 所有Spring应用 | 默认值,Ioc容器只存在单例 |
prototype | 所有Spring应用 | 每当从Ioc容器中取出一个bean,则创建一个新的bean |
session | Spring Web应用 | HTTP会话 |
application | Spring Web应用 | Web工程生命周期 |
request | Spring Web应用 | Web工程单次请求 |
globalSession | Spring Web应用 | 在一个全局的HTTP session中,一个bean定义对应一个实例。实践中基本不使用 |
常用的是加粗的4个。
Singleton(单例)和Prototype(原型)的区别
定义作用域类ScopeBean
package com.lay.ioc.scope.pojo;
import org.springframework.stereotype.Component;
@Component
//@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ScopeBean {
}
其中声明bean作用域为prototype的代码被注释掉了,所以默认为singleton单例的。
测试作用域
package com.lay.ioc.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.lay.ioc.IocApplication;
import com.lay.ioc.scope.pojo.ScopeBean;
public class IoCTest {
private static Logger log = LoggerFactory.getLogger(IocApplication.class);
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(AppConfig.class);
ScopeBean scopeBean1=ctx.getBean(ScopeBean.class);
ScopeBean scopeBean2=ctx.getBean(ScopeBean.class);
System.out.println(scopeBean1==scopeBean2);
}
}
结果
true
如果把上面的注释掉的代码放开,声明prototype,结果
false
这里的ConfigurableBeanFactory只能提供单例(SCOPE_SINGLETON)单例和(SCOPE_PROTOTYPE)原型两种作用域供选择,如果是在Spring MVC环境中,还可以使用WebApplicationContext去定义其他作用域,如请求(SCOPE_REQUEST)、会话(SCOPE_SESSION)和应用(SCOPE_APPLICATION)
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
@Component
//@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class ScopeBean {
}
这样同一个请求范围内去获取这个Bean的时候。只会共同用一个Bean。第二次请求就会产生新的Bean。因此两个不同的请求将不得不同的实例的Bean。