@Scope注解 详细讲解及示例


1.@Scope注解是什么

  @Scope注解是 Spring IOC 容器中的一个作用域,在 Spring IOC 容器中,他用来配置Bean实例的作用域对象。@Scope 具有以下几种作用域:

  1. singleton 单实例的(单例)(默认)   ----全局有且仅有一个实例
  2. prototype 多实例的(多例)   ---- 每次获取Bean的时候会有一个新的实例
  3. reqeust    同一次请求 ----request:每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效
  4. 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时长增加。


博主写作不易,加个关注呗

求关注、求点赞,加个关注不迷路 ヾ(◍°∇°◍)ノ゙

我不能保证所写的内容都正确,但是可以保证不复制、不粘贴。保证每一句话、每一行代码都是亲手敲过的,错误也请指出,望轻喷 Thanks♪(・ω・)ノ

  • 84
    点赞
  • 200
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

扛麻袋的少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值