Spring学习记录之Bean的作用域

发布时间 2024-01-01 14:37:51作者: zhao-XH

Spring学习记录之Bean的作用域


前言

这篇文章是我第二次学习b站老杜spring相关课程所进行的学习记录,算是对课程内容及笔记的二次整理,以自己的理解方式进行二次记录,其中理解可能存在错误,欢迎且接受各位大佬们的批评指正;

关于本笔记,只是我对于相关知识遗忘时快速查阅了解使用,至于课程中实际实验配置等,也只是记录关键,并不会记录详细步骤,若想了解可以关注我博客的项目经验模块,我会在实际项目开发过程中总结项目经验,在该模块发布!

学习视频地址:https://www.bilibili.com/video/BV1Ft4y1g7Fb/

视频配套笔记:https://www.yuque.com/dujubin/ltckqu/kipzgd?singleDoc# 《Spring6》 密码:mg9b


目录


一、我个人对这部分学习的一些见解

这部分主要讲述Spring管理的Bean的作用域,即BeanSpring容器中是单例还是多例等;以及如何自定义Bean的作用域。这部分是需要重点了解的内容,学习完Spring后要有Bean作用域的概念。

这部分我会继续引用老杜的笔记。

二、Bean的作用域

① singleton(单例)

默认情况下,Spring的IoC容器创建的Bean对象是单例的。来测试一下:

SpringBean

package com.powernode.spring6.beans;

/**
 * @author 动力节点
 * @version 1.0
 * @className SpringBean
 * @since 1.0
 **/
public class SpringBean {
}

spring-scope.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">

    <bean id="sb" class="com.powernode.spring6.beans.SpringBean" />
    
</beans>

测试程序:

@Test
public void testScope(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-scope.xml");

    SpringBean sb1 = applicationContext.getBean("sb", SpringBean.class);
    System.out.println(sb1);

    SpringBean sb2 = applicationContext.getBean("sb", SpringBean.class);
    System.out.println(sb2);
}

执行结果:

img

通过测试得知:Spring的IoC容器中,默认情况下,Bean对象是单例的。

这个对象在什么时候创建的呢?可以为SpringBean提供一个无参数构造方法,测试一下,如下:

SpringBean

package com.powernode.spring6.beans;

/**
 * @author 动力节点
 * @version 1.0
 * @className SpringBean
 * @since 1.0
 **/
public class SpringBean {
    public SpringBean() {
        System.out.println("SpringBean的无参数构造方法执行。");
    }
}

将测试程序中getBean()所在行代码注释掉:

测试程序:

@Test
public void testScope(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-scope.xml");
}

执行测试程序:

img

通过测试得知,默认情况下,Bean对象的创建是在初始化Spring上下文的时候就完成的。

② prototype(多例)

如果想让SpringBean对象以多例的形式存在,可以在bean标签中指定scope属性的值为:prototype,这样Spring会在每一次执行getBean()方法的时候创建Bean对象,调用几次则创建几次。(默认单例只在容器初始化的时候创建一次被管理的Bean对象)

spring-scope.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">

    <bean id="sb" class="com.powernode.spring6.beans.SpringBean" scope="prototype" />

</beans>

测试程序:

@Test
public void testScope(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-scope.xml");

    SpringBean sb1 = applicationContext.getBean("sb", SpringBean.class);
    System.out.println(sb1);

    SpringBean sb2 = applicationContext.getBean("sb", SpringBean.class);
    System.out.println(sb2);
}

执行结果:

img

我们可以把测试代码中的getBean()方法所在行代码注释掉:

测试代码:

@Test
public void testScope(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-scope.xml");
}

执行结果:

img

可以看到这一次在初始化Spring上下文的时候,并没有创建Bean对象。

那你可能会问:scope如果没有配置,它的默认值是什么呢?默认值是singleton,单例的。

spring-scope.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">

    <bean id="sb" class="com.powernode.spring6.beans.SpringBean" scope="singleton" />

</beans>

测试程序:

@Test
public void testScope(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-scope.xml");

    SpringBean sb1 = applicationContext.getBean("sb", SpringBean.class);
    System.out.println(sb1);

    SpringBean sb2 = applicationContext.getBean("sb", SpringBean.class);
    System.out.println(sb2);
}

执行结果:

img

通过测试得知,没有指定scope属性时,默认是singleton单例的。

三、其它scope(作用域)

scope属性的值不止两个,它一共包括8个选项:

  • singleton:默认的,单例。
  • prototype:原型。每调用一次getBean()方法则获取一个新的Bean对象。或每次注入的时候都是新对象。
  • request:一个请求对应一个Bean仅限于在WEB应用中使用
  • session:一个会话对应一个Bean仅限于在WEB应用中使用
  • global sessionportlet应用中专用的。如果在ServletWEB应用中使用global session的话,和session一个效果。(portletservlet都是规范。servlet运行在servlet容器中,例如Tomcatportlet运行在portlet容器中。)
  • application:一个应用对应一个Bean仅限于在WEB应用中使用。
  • websocket:一个websocket生命周期对应一个Bean仅限于在WEB应用中使用。
  • 自定义scope:很少使用。

接下来咱们自定义一个Scope,线程级别的Scope,在同一个线程中,获取的Bean都是同一个。跨线程则是不同的对象:(以下内容作为了解)

  • 第一步:自定义Scope。(实现Scope接口)

    • spring内置了线程范围的类:org.springframework.context.support.SimpleThreadScope,可以直接用。
  • 第二步:将自定义的Scope注册到Spring容器中。

    spring-scope.xml

    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
      <property name="scopes">
        <map>
          <entry key="myThread">
            <bean class="org.springframework.context.support.SimpleThreadScope"/>
          </entry>
        </map>
      </property>
    </bean>
    
  • 第三步:使用Scope。

    spring-scope.xml

    <bean id="sb" class="com.powernode.spring6.beans.SpringBean" scope="myThread" />
    

    编写测试程序:

    @Test
    public void testCustomScope(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-scope.xml");
        SpringBean sb1 = applicationContext.getBean("sb", SpringBean.class);
        SpringBean sb2 = applicationContext.getBean("sb", SpringBean.class);
        System.out.println(sb1);
        System.out.println(sb2);
        // 启动线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                SpringBean a = applicationContext.getBean("sb", SpringBean.class);
                SpringBean b = applicationContext.getBean("sb", SpringBean.class);
                System.out.println(a);
                System.out.println(b);
            }
        }).start();
    }
    

    执行结果:

    img

四、总结

这部分我们了解到:

  • SpringIoC容器中,默认情况下,Bean对象是单例的!
  • 默认情况下,SpringBean对象的创建是在初始化Spring上下文的时候就完成的。
  • scope属性的值不止两个,它一共包括8个选项。均在特定的情况下使用。
  • 如果框架提供的作用域不符合要求,还可以自定义Bean的作用域。

这里需要去了解老杜这节相关讲解,可以直接点击下面链接跳转到对应课程学习了解!

037-bean作用域之单例和多例_哔哩哔哩_bilibili