概述
在默认情况下,Spring 应用上下文中所有 bean 都是作为以单例(singleton)的形式创建的。也就是说,不管给定的一个 bean 被注入到其他 bean 多少次,每次所注入的都是同一个实例。但是对于易变的类型而言,这并不合适,我们需要使用使用@Scope 注解来配置,它可以与 @Component 或 @Bean 一起使用。
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Notepad { ... }
总结
典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效
其中比较常用的是singleton和prototype两种作用域。对于singleton作用域的Bean,每次请求该Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使用new 关键字创建Bean实例,一旦创建成功,容器不在跟踪实例,也不会维护Bean实例的状态。
如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在创建Java实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此,prototype作用域Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,可以重复使用。因此,除非必要,否则尽量避免将Bean被设置成prototype作用域。
singleton 单例
在不指定@Scope的情况下,所有的bean都是单实例的bean,而且是饿汉加载(容器启动实例就创建好了),IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例,如果想变成懒加载(第一次使用bean的时候才会去触发)的话只需要添加@Lazy注解即可.
这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中 只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时 候,spring的IOC容器中只会存在一个该bean。
singleton需要考虑线程安全问题.
Prototype 原型模式(多例)
指定@Scope为 prototype 表示为多实例的,而且还是懒汉模式加载(IOC容器启动的时候,并不会创建对象,而是在第一次使用的时候才会创建)
每次注入或者通过Spring应用上下文调用getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例(相当于一个new新对象的操作),才会初始化,然后就会触发构造方法.
对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。 清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用 bean的后置处理器,该处理器持有要被清除的bean的引用。)
另外需要注意的是,singleton Bean 引用prototype Bean 时的陷阱,开发人员不能依赖注入一个prototype 范围的bean到自己的singleton Bean 中,因为这个注入只发生一次,就是当Spring容器正在实例化singleton Bean并解析和注入它的依赖时,如果在运行时不止一次需要一个prototype bean的新势力,可以采用方法注入的方式.
注意: prototype 模式是不能解决IOC的循环依赖的.
request 请求
日常开发使用比较少
request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,该生命周期的对象和request生命周期保持一致的.
配置实例:
request、session、global session使用的时候首先要在初始化web的web.xml中做如下配置:
request作用域的bean是存放在Request域对象里面的,
session 会话
日常开发使用比较少
在Web应用中,为每个会话创建一个bean实例。
在一次Http Session中,容器会返回该Bean的同一实例。而对不同的Session请求则会创建新的实例,该bean实例仅在当前Session内有效。
session作用域的Bean对象是存放在Session里面的.
application
定义了每个ServletContext有一个实例
globalsession
仅仅在基于portlet的web应用中才有意义. (Portal是一个基于Web的应用)
每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。
global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。
请注意,假如你在编写一个标准的基于Servlet的web应用,并且定义了一个或多个具有global session作用域的bean,系统会使用标准的HTTP Session作用域,并且不会引起任何错误。
webSocket
定义了每个WebSocket有一个实例,只有在使用Web功能的Spring ApplicationContext时才有效.
2.@Lazy
Bean的懒加载@Lazy(主要针对单实例的bean 容器启动的时候,不创建对象,在第一次使用的时候才会创建该对象),注意只有singleton的时候才会生效.
@Bean
@Lazy
public Person person() {
return new Person();
}
3.自定义scope
案例:ZJJSpring_2020/01/27 0:42:02_h21v3 |
---|
注册scope到Spring容器里面
https://www.yuque.com/docs/share/c070b7e1-54a3-4c06-879e-759025e31e6e?#