@Scope注解是 Spring IOC 容器中的一个作用域
,在 Spring IOC 容器中,他用来配置Bean实例的作用域对象。@Scope 具有以下几种作用域:
- singleton 单实例的(
单例
)(默认) ----全局有且仅有一个实例- prototype 多实例的(
多例
) ---- 每次获取Bean的时候会有一个新的实例- reqeust 同一次请求 ----request:每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前
HTTP request
内有效- session 同一个会话级别 ---- session:每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前
HTTP session
内有效
注:这边只演示我们常用的 singleton、prototype 两种,其他的可以自己试试
直接在bean对象方法上增加@Scope注解即可。
① 在不指定@Scope的情况下,所有的bean都是单实例的bean,而且是饿汉
模式加载(容器启动实例就创建好了)
@Bean
public Person person() {
return new Person();
}
②指定@Scope为 prototype
表示为多实例的,而且还是懒汉
模式加载(IOC容器启动的时候,并不会创建对象,而是 在第一次使用的时候才会创建)
@Bean
@Scope(value = "prototype")
public Person person() {
return new Person();
}
/**
* Person类
*/
public class Person {
// Person类无参构造方法
public Person() {
System.out.println("执行Person构造器创建Person对象");
}
}
/**
* TODO 主配置类
*
* @author : lzb
* @date: 2021-03-05 13:50
*/
@Configuration
public class BeanConfig {
@Bean
@Scope(value = "singleton")
public Person person(){
return new Person();
}
}
@Scope注解默认为singleton
单例,singleton实例的意思不管你使用多少次在springIOC容器中只会存在一个实例,演示如下只打印了一次创建实例:
public class DemoApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(BeanConfig.class);
Person person = ac.getBean(Person.class);
Person person2 = ac.getBean(Person.class);
System.out.println(person);
System.out.println(person2);
System.out.println(person == person2);
}
}
执行结果:
可以发现singleton单例模式,在IOC容器中只会有一个实例存在,每次getBean()获取的实例对象都是同一个。
/**
* TODO 主配置类
*
* @author : lzb
* @date: 2021-03-05 13:50
*/
@Configuration
public class BeanConfig {
@Bean
@Scope(value = "prototype")
public Person person(){
return new Person();
}
}
执行结果:
发现prototype多例模式,每次在调用getBean() 获取实例时,都会重新调用 Person 类的无参构造方法,重新创建一个 Person 对象。
使用singleton单例,采用饿汉加载(容器启动,Bean实例就创建好了)
使用prototype多例,采用懒汉加载(IOC容器启动的时候,并不会创建对象实例,而是在第一次使用的时候才会创建)
/**
* TODO 主配置类
*
* @author : lzb
* @date: 2021-03-05 13:50
*/
@Configuration
public class BeanConfig {
@Bean
@Scope(value = "singleton")
public Person person(){
return new Person();
}
}
public class DemoApplication {
public static void main(String[] args) {
// 启动Spring IOC容器
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(BeanConfig.class);
}
}
执行结果:
singleton单例模式,在 IOC 容器启动时,便会去调用 Person 类的无参构造方法,创建一个 Person 对象。此时并没有调用 getBean() 方法来获取Person 对象实例。所以singleton 采用的是 恶汉式 创建实例对象
注:如何将 singleton 单例模式的 恶汉式
变更为 懒汉式
,只需要再添加一个 @Lazy 注解即可。 如下所示:
@Configuration
public class BeanConfig {
@Bean
@Scope
@Lazy
public Person person(){
return new Person();
}
}
/**
* TODO 主配置类
*
* @author : lzb
* @date: 2021-03-05 13:50
*/
@Configuration
public class BeanConfig {
@Bean
@Scope(value = "prototype")
public Person person(){
return new Person();
}
}
public class DemoApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(BeanConfig.class);
System.out.println("=================IOC容器启动成功==============");
Person person = ac.getBean(Person.class);
System.out.println(person);
}
}
执行结果:
prototype多例模式,在 IOC 容器启动时,并不会去创建Bean实例,只有在调用 getBean() 方法获取Person 对象时,才会去调用 Person 类的无参构造方法,创建一个 Person 对象。所以 prototype 采用的是 懒汉式 创建实例对象
针对单实例bean的话,容器启动的时候,bean的对象就创建了,而且容器销毁的时候,也会调用Bean的销毁方法;
针对多实例bean的话,容器启动的时候,bean是不会被创建的而是在获取bean的时候被创建,而且bean的销毁不受IOC容器的管理,是由GC来处理的
针对每一个Bean实例,都会有一个initMethod() 和 destroyMethod() 方法,我们可以在Bean 类中自行定义,也可以使用 Spring 默认提供的这两个方法。
public class Person {
public Person() {
System.out.println("执行Person构造器创建Person对象");
}
public void init() {
System.out.println("initMethod");
}
public void destroy() {
System.out.println("destroyMethod");
}
}
@Configuration
public class BeanConfig {
@Bean(initMethod = "init", destroyMethod = "destroy") // 可以自己指定方法名,也可以不指定,使用Spring默认提供的方法
@Scope(value = "singleton")
public Person person(){
return new Person();
}
}
singleton单例,在IOC容器销毁时,就会调用 destroyMethod() 方法来将 Bean对象销毁;prototype多例,它的Bean实例对象则不受IOC容器的管理,最终由GC来销毁。
几乎90%以上的业务使用 singleton单例就可以,所以 Spring 默认的类型也是singleton,singleton虽然保证了全局是一个实例,对性能有所提高,但是如果实例中有非静态变量时,会导致线程安全问题,共享资源的竞争。
当设置为prototype多例时:每次连接请求,都会生成一个bean实例,也会导致一个问题,当请求数越多,性能会降低,因为创建的实例,导致GC频繁,GC时长增加。
博主写作不易,加个关注呗
求关注、求点赞,加个关注不迷路 ヾ(◍°∇°◍)ノ゙
我不能保证所写的内容都正确,但是可以保证不复制、不粘贴。保证每一句话、每一行代码都是亲手敲过的,错误也请指出,望轻喷 Thanks♪(・ω・)ノ