面试官:聊一聊 Spring 中 Bean 的作用域
今天分享一下 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。
标注类
使用 @Component,@Service 等注解定义 bean 时,设置作用域直接在类上添加 @Scope。
获取 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 的创建和获取从源码和白话进行大体的分析。
作者:刘牌
链接:https://juejin.cn/post/7218369118788059196
来源:稀土掘金
评论