前言
今天分享一下spring bean的作用域,理解bean的作用域能够在使用过程中避免一些问题,bean的作用域也是spring bean创建过程中一个重要的点。
Spring bean的作用域类型
-
singleton(单例模式):在整个应用程序的生命周期中,只创建一个Bean实例。默认情况下,所有的Bean都是单例模式。
-
prototype(原型模式):每次请求Bean时都会创建一个新的实例。
-
request(请求模式):每次HTTP请求都会创建一个新的实例,该作用域仅适用于Web应用程序的Spring MVC应用程序。
-
session(会话模式):每个用户会话都有一个Bean实例,该作用域仅适用于Web应用程序的Spring MVC应用程序。
-
globalSession(全局会话模式):用于Portlet应用程序,一个全局会话有一个Bean实例。
-
application(应用程序模式):在Web应用程序上下文中,只创建一个Bean实例。
从上面我们能看出spring有很多种作用域,不过在实际使用中,我们基本都使用单例bean,这也是spring bean的默认作用域,单例bean能提高性能,因为全局只存在一个bean实例,而多例bean则每次请求都需要创建bean实例,当并发比较大的时候,就会比较影响性能,所以这时候就需要使用单例bean,但是单例bean可能会存在线程安全问题,当bean中存在可变的成员变量时,就会存在线程安全问题,而多例bean因为每次都会创建一个实例,所以不存在bean共享,就不存在线程安全问题。
使用作用域
现在我们基本都是使用SpringBoot,都是基于注解开发,我们可以使用注解@Scope设置bean的作用域,可以标注在类上和方法上。
标注方法
当我们使用@Bean定义Bean的时候,设置作用域可以直接在方法上面使用@Scope。
@Bean
@Scope("prototype")
public ScopeBean scopeBean()
return new ScopeBean();
标注类
使用@Component,@Service等注解定义bean时,设置作用域直接在类上添加@Scope。
@Component
@Scope("prototype")
public class ScopeBean
获取bean和创建bean
如果是单例bean,在spring容器启动的时候会将Bean注册进IOC容器中,如果是多例bean,则不注册进IOC容器中。
bean在实例化前会把bean的基础信息组装成BeanDefinition,然后保存到BeanFactory中,如果是单例的bean,则会继续对bean处理后将bean注册到IOC容器中,如果是多例bean,则不注册进,当从IOC容器中获取bean时,如果是单例则从IOC容器中获取已经创建好的bean,如果是多例,则从BeanFactory中获取bean的定义信息BeanDefinition,然后重复和单例bean一样的步骤创建bean,只是创建后它不会保存进IOC容器,而是直接返回。
作用域和懒加载
如果bean设置为懒加载(Lazy)和单例bean,那么bean在spring启动时不会注册进容器中,而是等第一次获取bean的时候在创建bean,后面获取bean的时候再从IOC容器中获取,如果设置为多例bean,那么懒加载其实是没用的。
源码解析
源码比较简单,其实就是判断bean的类型,然后再进入不同的逻辑进行处理,在AbstractBeanFactory中,通过doGetBean()方法获取bean。
判断bean是否存在容器中
下图通过getSingleton()方法从singletonObjects中获取bean,如果获取到直接返回,代表bean已经创建过勒,已经存在与IOC容器中,singletonObjects就是整个spring中装bean实例的容器,他就是一个Map,spring整个bean的创建过程目的就是把bean放进它里面,所以spring简单得不行,但是更复杂得不行
。
bean不存在,则创建
下图有两个判断,判断单例bean和多例bean,单例bean会创建bean后然后加入到singletonObjects中,多例bean则直接返回,他们的创建都是走同一个方法,同一样的流程。
具体的创建流程就不一一细说,只是从大体思路去讲解,因为往里面说就贴出大篇代码,没啥必要,感兴趣可以去看源码。
总结
上面说了bean的作用域类型,并对每种作用域类型进行分析,最常用的其实就是单例,并对多例和单例使用过程中的一些注意事项进行讲解,接着说了怎么使用作用域,还有懒加载和作用域的关联,并对bean的创建和获取从源码和白话进行大体的分析。
今天的分享就到这里,感谢你的观看,我们下期见!
spring:bean的作用域
Spring定义了多种作用域,可以基于这些作用域创建bean,包括:
单例(Singleton):在整个应用中,只创建bean的一个实例。
原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
会话(Session):在Web应用中,为每个会话创建一个bean实例。
请求(Rquest):在Web应用中,为每个请求创建一个bean实例。
@Componet
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Notepad{....}
这里,使用ConfigurableBeanFactory类的SCOPE_PROTOTYPE常量设置了原型作用域。你当然也可以使
用@Scope("prototype"),但是使用SCOPE_PROTOTYPE常量更加安全并且不易出错。