Spring详解(十一)----Bean 的作用域

1、Bean 的作用域介绍

       默认情况下,Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一 一个实例,并且整个 IOC 容器范围内都能共享该实例,所有后续的对象通过getBean() 调用和 Bean 的引用都将返回这个唯一的 Bean 实例。但是如果我们需要不同实例的Bean呢?这时就要提到Bean的作用域了,在Spring中默认的作用域为 Singleton,它是所有 Bean 的默认作用域。而在Spring 中提供了 5 种作用域,它会根据情况来决定是否生成新的对象,如下:

  1. singleton:单例模式,这是 Bean 默认的作用域,使用 singleton 定义的 Bean 在整个 Spring 容器生命周期内只创建这一个 Bean。
  2. prototype:原型模式(多例模式),Spring 容器初始化时不创建 Bean 的实例,而在每次通过getBean获取Bean时都创建一个新的Bean实例并返回。
  3. request:请求模式,用于Web开发,在一次 HTTP 请求中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Request 内有效。
  4. session:会话模式,用于Web开发,在一次 HTTP Session 中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Session 内有效。
  5. global Session(Spring5已经去除了):全局会话模式,在一个全局的 HTTP Session 中,容器会返回该 Bean 的同一个实例。该作用域仅在使用 portlet context 时有效。一般用于 Porlet 应用环境 , 分布式系统存在全局 session 概念(单点登录),如果不是 porlet 环境,globalSession 等同于 Session。

       =====================================

       我们可以通过XML<bean> 元素中的 scope 属性 或者 @Scope 注解 来设置Bean的作用域,例如:

  • XML 中设置作用域:<bean id="" class="" scope="prototype" />
  • 注解设置作用域: @Scope("prototype") 或者 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

       在上述五种作用域中,实际开发中 singleton 和 prototype 是最常用的两种。

2、XML配置举例

       ①、首先创建一个User类,代码如下:

/**
 * 用户实体类
 */
public class User {
    private int userId;
    private String userName;
    private int userAge;
    private String userPwd;
    private String userAddress;

    //getter、setter省略...(这里就不要toString方法了,因为要打印对象的地址)
}

       ②、在 Spring 的配置文件我们将 scope 属性的值设置为 prototype 多例模式,xml如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--创建一个User实例,作用域设置为prototype 多例模式-->
    <bean id="user" class="com.thr.pojo.User" scope="prototype"/>
</beans>

       ③、测试代码,这里分别获取了三个User对象:

/**
 * 测试代码
 */
public class SpringTest {
    public static void main(String[] args) {
        //1.初始化Spring容器,加载配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.通过容器获取实例
        User user1 =  applicationContext.getBean("user", User.class);
        User user2 =  applicationContext.getBean("user", User.class);
        User user3 =  applicationContext.getBean("user", User.class);
        //3.调用实例中的属性
        System.out.println(user1);
        System.out.println(user2);
        System.out.println(user3);
    }
}

       ④、运行测试代码,查看控制台打印的结果:

image

       可以很明显的发现,这三个User对象的地址是不一样的,说明分别创建了三个不同的User对象。

3、注解配置举例

       ①、首先创建一个User类,代码参考上面的。

       ②、创建PojoConfig类,用来启动容器和注册Bean对象:

/**
 * 启动容器和注册Bean对象
 */
@ComponentScan(basePackages = "com.thr.pojo")
@Configuration
public class PojoConfig {
    public PojoConfig() {
        System.out.println("PojoConfig容器初始化成功...");
    }

    //实例化User对象
    @Bean(name = "user")
    //显示设置单例模式
    @Scope(value = "singleton")
    public User user(){
        return new User();
    }
}

       ③、测试代码,这里分别获取了三个User对象,注意这里需要使用AnnotationConfigApplicationContext类来获取:

/**
 * 测试代码
 */
public class SpringTest1 {
    public static void main(String[] args) {
        //1.初始化Spring容器,通过注解加载
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(PojoConfig.class);
        //2.通过容器获取实例
        User user1 =  applicationContext.getBean("user", User.class);
        User user2 =  applicationContext.getBean("user", User.class);
        User user3 =  applicationContext.getBean("user", User.class);
        //3.调用实例中的属性
        System.out.println(user1);
        System.out.println(user2);
        System.out.println(user3);
    }
}

       ④、运行测试代码,查看控制台打印的结果:

image

       由于注册 Bean 时Scope设置为 singleton 单例模式,所以创建的多个 User 肯定是同一个,可以发现结果是一样的。

原文地址:https://www.cnblogs.com/tanghaorong/p/14185723.html