Spring中的@Scope注解详细讲解及示例
作者:扛麻袋的少年
1.@Scope注解是什么
@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 两种,其他的可以自己试试
2.@Scope注解怎么使用
直接在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(); }
3.singleton/prototype模式演示
/** * 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(); } }
3.1 singleton单例演示
@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()获取的实例对象都是同一个。
3.2 prototype多例演示
/** * 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 对象。
4.恶汉/懒汉
使用singleton单例,采用饿汉加载(容器启动,Bean实例就创建好了)
使用prototype多例,采用懒汉加载(IOC容器启动的时候,并不会创建对象实例,而是在第一次使用的时候才会创建)
4.1 singleton 恶汉
演示
/** * 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(); } }
4.2 prototype 懒汉
演示
/** * 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 采用的是 懒汉式 创建实例对象
5.Bean实例对象的销毁
针对单实例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来销毁。
6.@Scope注解的使用场景
几乎90%以上的业务使用 singleton单例就可以,所以 Spring 默认的类型也是singleton,singleton虽然保证了全局是一个实例,对性能有所提高,但是如果实例中有非静态变量时,会导致线程安全问题,共享资源的竞争。
当设置为prototype多例时:每次连接请求,都会生成一个bean实例,也会导致一个问题,当请求数越多,性能会降低,因为创建的实例,导致GC频繁,GC时长增加。
到此这篇关于Spring中的@Scope注解详细讲解及示例的文章就介绍到这了,更多相关Spring中的@Scope注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!