SpringBoot Bean的作用域
在Spring Ioc容器最顶级接口BeanFactory中, 可以看到 isSingleton 和 isPrototype 两个方法, 其中, 如果 isSingleton 返回true, 则Bean在Ioc容器中是以单例的状态存在的, 这也是Spring Ioc容器的默认值, 如果 isPrototype 返回true, 则当我们每次获取Bean的时候, Ioc容器都会创建一个新的Bean, 这显然存在很大的不同, 这就是Spring Bean的作用域问题. 在一般的容器中, Bean多会存在 单例 和 多例 两种作用域, JavaEE广泛的使用在互联网, 而在Web容器中, 则存在页面page, 请求request, 会话session 和 应用application 4种作用域, 对于页面page, 是针对JSP当前页面的作用域, 所以Spring无法支持, 为了满足各类的作用域, 在Spring的作用域中就存在如下的几种类型
表3-1的作用域中, 常用的是加粗的4种, 对于application作用域, 完全可以使用单例来代替
下面探讨单例和原型的区别
@SpringBootTest
@RunWith(SpringRunner.class)
public class ScopeBeanTest {
@Autowired
ApplicationContext context;
@Test
public void test() {
ScopeBean bean1 = context.getBean(ScopeBean.class);
ScopeBean bean2 = context.getBean(ScopeBean.class);
System.out.println(bean1 == bean2);
}
}
@Component
// @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
class ScopeBean {
}
上面代码中使用Junit来进行测试, 定义了简单的类ScopeBean, 类上注解@Scope已经被注释掉了, 这样就使用了默认的单例作用域, 然后我们运行test方法, 从容器中获取两次ScopeBean的Bean, 然后测试bean1==bean2, 此时测试的结果是true, 说明bean1和bean2两个Bean指向了同一个Bean的实例, 所以容器中只有一个Bean, 此时在将注解@Scope放开, 测试结果为false, 因为作用域被改为了原型, 每次获取的都是一个新的实例, 所以bean1==bean2结果为false
注意, 这里@Scope注解中的ConfigurableBeanFactory, 只能提供单例(SCOPE_SINGLETON)和原型(SCOPE_PROTOTYPE)两种作用域, 如果实在SpringMVC环境中, 还可以使用WebApplicationContext去定义其他的作用域, 如请求(SCOPE_REQUEST), 会话(SCOPE_SESSION) 和 应用(SCOPE_APPLICATION)