spring源码阅读3-1——bean的作用域

java开发者都会在实体对象的属性中加上private关键字,而在业务类对外发放的方法中写上public关键字,这并不是习惯,而是开发者深谙其道,这就是java对象中filed的作用域。
举个例子,你家里的东西,都属于你家的,家门前的路是属于你和邻居们的,你爸爸的剃须刀是属于你爸爸的;这就是作用域,分清对象归属权限的作用。
而在spring容器所管理的组件,也是有作用域的。本章将会详细阐述bean的作用域,以及其和ApplicationContext、bean和beanFactory丝丝缕缕的联系。

俗话说,授之于鱼不如授之以渔,我们还是通过源码来学习,希望在这个过程大家都能够有所提升。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {

    /**
     * Specifies the scope to use for the annotated component/bean.
     * @see ConfigurableBeanFactory#SCOPE_SINGLETON
     * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
     * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
     * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
     */
    String value() default ConfigurableBeanFactory.SCOPE_SINGLETON;

    /**
     * Specifies whether a component should be configured as a scoped proxy
     * and if so, whether the proxy should be interface-based or subclass-based.
     * <p>Defaults to {@link ScopedProxyMode#NO}, indicating that no scoped
     * proxy should be created.
     * <p>Analogous to {@code <aop:scoped-proxy/>} support in Spring XML.
     */
    ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;

}

在spring容器中,@Scope注解来声明实例的作用域,在源码中的注释中有这样一句话In this context, scope means the lifecycle of an instance。scope决定了实例的整个生命周期。

Scope注解的value值上方的注释告诉我们,当前有四个值:(高级版本更新了global session)
SCOPE_SINGLETON,SCOPE_PROTOTYPE,SCOPE_REQUEST,SCOPE_SESSION,下面分别来看看,这些作用域,有什么不同。

SCOPE_SINGLETON:

从源码中可以看到,该作用域是spring默认的作用域。`singleton`想必大家都非常熟悉,没错,学习设计模式的时候第一个介绍的应该就是单例模式,也就是说,spring中的bean,默认情况下都是单例。复习下什么是单例:在应用中,有且只有一个实例。通过之前的bean管理的学习([《spring源码阅读2-2——bean的管理》](http://www.jianshu.com/p/3c225fc067a0)),我们知道容器中的单例都会被注册到spring容器中的缓存中,回顾下:
容器中的缓存对象

这回可以动态运行demo代码,证实下spring容器对于bean的管理。

//代码清单 1-1配置文件
com.nd.config.SpringConfig

@Configuration
@ComponentScan(basePackages = {"com.nd"})
public class SpringConfig {
}

//代码清单 1-2 main函数
com.nd.HelloApp

public class HelloApp {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        HelloService helloService = context.getBean(HelloService.class);
        System.out.println(helloService.sayHello());
    }
}

//代码清单 1-3 bean
com.nd.HelloService

@Component
public class HelloService {
    public String sayHello() {
        return "Hello world!";
    }
}

代码很简单,之前用的xml配置也被替换成注解配置了。
通过IDEA的debug功能,查看context的内容:

context下的beanFactory
singletonObjects与registeredSingletons

可以看到确实如之前所说,singletonObjects存放注册后的实例,而registeredSingletons存放的是注册实例的名称(类型是String)。而我们的组件helloService也在其中,这时候通过getBean方法就能够获取到该实例,运行程序,便可以看到我们最熟悉的Hello world!

SCOPE_PROTOTYPE

这个也很熟悉对吧,设计模式中有个原型模式。顾名思义,每一次获得的实例都是一个原型的拷贝(新的对象)。
我们看下这个给bean加上这个注解

@Component
@Scope(value = "prototype")
public class HelloService {
    public String sayHello() {
        return "Hello world!";
    }
}

运行后再观察singletonObjects,已经没有注册该实例了。

只有14个注册的实例

但是程序运行结果依然是输出了最熟悉的Hello world!(具体如何实现日后会有机会展示的),这就是原型作用域的作用。

单例和原型的比较

曾经有一位前辈问过我,spring中的service对象是单例还是多实例,我自信地说出是单例。他接着追问,为什么是单例?我支支吾吾答不上来,好像明白,又好像不是那么的清晰。
其实原因很简单,这要从单例和原型的区别说起。单例是整个是在spring容器初始化的时候就被添加入到容器中,直到容器销毁,单例也随之销毁,典型的人在塔在。优势应该很容易看出来,单例模式,你要用的时候就已经存在,不需要生成实例,配合spring的DI特性(依赖注入),能够让程序快速的响应,提高性能。而劣势就在于单例是常驻内存,存在内存泄露的问题,而且单例存在变量污染的问题。而service、dao属于业务代码,业务代码的原子性避免变量污染的问题,业务代码在内存和性能的较量上明显是利大于弊的。因此业务代码理所当然的就是单例了。
那什么情况下使用原型?当然是容易被污染的对象必须使用原型了,比如数据实体对象,迭代器等。

SCOPE_REQUEST & SCOPE_SESSION

随着spring的发展以及在web应用中的广泛应用,作用域也随之增加。
SCOPE_REQUEST在每一次请求时生成实例,而在请求结束时销毁,而SCOPE_SESSION是在每一次会话过程中生成实例会话结束后销毁。由于本文章基于spring application,对于web相关的内容会在以后的文章中阐述,这里就简单带过了。别问我请求和会话是什么概念,百度去吧~

总结:
对作用域的理解还是有很大的作用的,在很多情况下,勿用甚至滥用单例容易造成很多问题(看劣势:变量污染、内存泄露)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容