Spring Bean的作用域具体实现(单例、多例、请求、会话、Application)

 更新时间:2025年08月06日 10:52:02   作者:椰椰椰耶  
文章讲解了Spring IoC/ DI中Bean作用域的管理方式,涵盖单例(singleton)、原型(prototype)及Web环境的request、session、application作用域,通过注解和配置区分不同作用域的实例创建规则,并通过测试验证其生命周期与共享特性,感兴趣的朋友一起看看吧

概念

Spring Ioc&DI 戒断,我们学习了 Spring 是如何帮助我们管理对象的

  1. 通过 @Controller@Service@Repository@Component@Configuration@Bean 来声明 Bean 对象
  2. 通过 ApplicationContext 或者 BeanFactory 来获取对象
  3. 通过 @AutowiredSetter 方法或者构造方法等来为应用程序注入所依赖的 Bean 对象

我们来简单回顾一下

  1. 通过 @Bean 声明 bean,把 bean 存在 Spring 容器中
public class Dog {  
    private String name;  
    public void setName(String name) {  
        this.name = name;  
    }  
}
@Component  
public class DogBeanConfig {  
    @Bean  
    public Dog dog() {  
        Dog dog = new Dog();  
        dog.setName("旺旺");  
        return dog;  
    }  
}
  1. Spring 容器中获取 Bean
    • 通过在代码中直接注入 ApplicationContext 的方式
@SpringBootTest  
class ApplicationTests {  
    @Autowired  
    private ApplicationContext applicationContext;  
    @Test  
    void contextLoads() {  
        DogBeanConfig dog1 = applicationContext.getBean(DogBeanConfig.class);;  
        System.out.println(dog1);  
    }  
}

司改代码,从 Spring 容器中多次获取 Bean

@SpringBootTest  
class ApplicationTests {  
    @Autowired  
    private ApplicationContext applicationContext;  
    @Test  
    void contextLoads() {  
        DogBeanConfig dog1 = applicationContext.getBean(DogBeanConfig.class);;  
        System.out.println(dog1);  
        DogBeanConfig dog2 = applicationContext.getBean(DogBeanConfig.class);;  
        System.out.println(dog2);  
    }  
}

观察运行结果

发现输出的 bean 对象地址是一样的,说明每次从 Spring 容器中取出来的对象都是同一个

  • 这也是“单例模式
  • 单例模式:确保一个类只有一个实例,多次创建也不会创建出多个实例

Bean 的作用域是值 BeanSpring 框架中的某种行为模式

比如单例作用域:表示 Bean 在整个 Spring 中只有一份,它是全局共享的。那么当其他人修改了这个值之后,那么另一个人读到的就是被修改后的值

修改上述代码,给 UserController 添加属性 name

@SpringBootTest  
class ApplicationTests {  
    @Autowired  
    private ApplicationContext applicationContext;  
    @Test  
    void contextLoads() {  
        Dog dog1 = applicationContext.getBean(Dog.class);  
        dog1.setName("狗狗1");  
        System.out.println(dog1);  
        System.out.println(dog1.getName());  
        Dog dog2 = applicationContext.getBean(Dog.class);;  
        System.out.println(dog2);  
        System.out.println(dog2.getName());  
    }  
}

观察运行结果:

  • dog1dog2 为同一个对象,dog2 拿到了 dog1 设置的值

那能不能将 bean 对象设置为非单例的(每次获取的 bean 都是一个新对象呢)

  • 这就是 Bean 的不同作用域了

Bean 的作用域

Spring 中支持 6 中作用域,后 4 种在 Spring MVC 环境才生效

  1. singleton:单例作用域
    • 每个 Spring Ioc 容器内同名称的 Bean 只有一个实例(单例)(默认)
  2. prototype:原型作用域(多例作用域)
    • 每次使用该 bean 时会创建新的实例(非单例)
  3. request:请求作用域
    • 每个 HTTP 请求生命周期内,创建新的实例(Web 环境中,了解)
  4. session:会话作用域
    • 每个 HTTP Session 生命周期内,创建新的实例(Web 环境中,了解)
  5. Application:全局作用域
    • 每个 ServletContext 生命周期里内,创建新的实例(web 环境中,了解)
  6. websocketHTTP WebSocket 作用域
    • 每个 WebSocket 生命周期内,创建新的实例(web 环境中,了解)

我们来看简单的代码实现

定义几个不同作用域的 bean

@Component  
public class DogBeanConfig {  
    @Bean  
    public Dog dog() {  
        Dog dog = new Dog();  
        dog.setName("旺旺");  
        return dog;  
    }  
    @Bean  
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)  
    public Dog singleDog() {  
        Dog dog = new Dog();  
        return dog;  
    }  
    @Bean  
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)  
    public Dog prototype() {  
        Dog dog = new Dog();  
        return dog;  
    }  
    @Bean  
    @RequestScope    
    public Dog requestDog() {  
        Dog dog = new Dog();  
        return dog;  
    }  
    @Bean  
    @SessionScope    
    public Dog sessionDog() {  
        Dog dog = new Dog();  
        return dog;  
    }  
    @Bean  
    @ApplicationScope    
    public Dog applicationDog() {  
        Dog dog = new Dog();  
        return dog;  
    }  
}
  • @RequestScope 等同于 @Scope (value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
  • @SessionScope 等同于 @Scope (value =WebApplicationContext.SCOPE_SESSION, proxyMode =ScopedProxyMode.TARGET_CLASS)
  • @ApplicationScope 等同于 @Scope (value =WebApplicationContext. SCOPE_APPLICATION, proxyMode =ScopedProxyMode. TARGET_CLASS)

proxyMode ⽤来为 springbean 设置代理 .proxyMode = ScopedProxyMode.TARGET_CLASS 表⽰这个 Bean 基于 CGLIB 实现动态代理,Requestsessionapplication 作⽤域的 Bean 需要设置 proxyMode

代码测试

测试不同作用域的 bean 取到的对象是否一样

@RestController  
public class DogController {  
    @Autowired  
    private Dog singleDog;  
    @Autowired  
    private Dog prototypeDog;  
    @Autowired  
    private Dog requestDog;  
    @Autowired  
    private Dog sessionDog;  
    @Autowired  
    private Dog applicationDog;  
    @Autowired  
    private ApplicationContext applicationContext;  
    @RequestMapping("/single")  
    public String single(){  
        Dog contexDog = (Dog) applicationContext.getBean("singleDog");  
        return "dog: " + singleDog.toString() + ", contextDog: " + contexDog;  
    }  
    @RequestMapping("/prototype")  
    public String prototype() {  
        Dog contextDog = (Dog) applicationContext.getBean("prototypeDog");  
        return "dog: " + prototypeDog.toString() + ", contextDog: " + contextDog;  
    }  
    @RequestMapping("/request")  
    public String request(){  
        Dog contexDog = (Dog) applicationContext.getBean("requestDog");  
        return "dog: " + requestDog.toString() + ", contextDog: " + contexDog;  
    }  
    @RequestMapping("/session")  
    public String session() {  
        Dog contextDog = (Dog) applicationContext.getBean("sessionDog");  
        return "dog: " + sessionDog.toString() + ", contextDog: " + contextDog;  
    }  
    @RequestMapping("/application")  
    public String application() {  
        Dog contextDog = (Dog) applicationContext.getBean("applicationDog");  
        return "dog: " + applicationDog.toString() + ", contextDog: " + contextDog;  
    }  
}
  • 每个请求都获取两次 Bean
  • @AutowiredapplicationContext.getBean("singleDog") 都是从 Spring 容器中获取对象

观察 Bean 的作用域

1.单例作用域

地址: http://127.0.0.1:8080/single

多次访问,得到的都是同一个对象,并且 @AutowiredapplicationContext.getBean() 也是同一个对象

2.多例作用域

地址: http://127.0.0.1:8080/prototype

观察 ContextDog,每次获取的对象都不一样(注入的对象在 Spring 容器启动时,就已经注入了,所以多次请求访问也不会发生变化)

3.请求作用域

地址: http://127.0.0.1:8080/request

在一次请求中,@AutowiredapplicationContext.getBean() 也是同一个对象,但是每次请求,都会重新创建对象

4.会话作用域

地址: http://127.0.0.1:8080/session

在一个 session 中,多次请求,获取到的对象都是同一个

换一个浏览器访问,发现会重新创建对象(另一个 session

5.Application作用域

地址: http://127.0.0.1:8080/application

在一个应用中,多次访问都是同一个对象

  • Application scope 就是对于整个 web 容器来说,bean 的作用域是 ServletContext 级别的
  • 这个和 singleton 有点类似,区别在于:Application scopeServletContext 的单例,singleton 是一个 ApplicationContext 的单例
  • 在一个 web 容器中 ApplicationContext 可以有多个(了解即可)

到此这篇关于Spring Bean的作用域具体实现(单例、多例、请求、会话、Application)的文章就介绍到这了,更多相关Spring Bean作用域内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springboot下实现RedisTemplate List 清空

    springboot下实现RedisTemplate List 清空

    我们经常会使用Redis的List数据结构来存储一系列的元素,当我们需要清空一个List时,可以使用RedisTemplate来实现,本文就来详细的介绍一下如何实现,感兴趣的可以了解一下
    2024-01-01
  • 示例解析java重载Overloading与覆盖Overriding

    示例解析java重载Overloading与覆盖Overriding

    这篇文章主要介绍了java重载Overloading与覆盖Overriding的示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • 非常全面的Java异常处理(全文干货,值得收藏)

    非常全面的Java异常处理(全文干货,值得收藏)

    这篇文章主要给大家介绍了非常全面的Java异常处理的相关资料,全文干货,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • 深入分析Spring BeanDefinition的构造元信息

    深入分析Spring BeanDefinition的构造元信息

    Bean Definition是一个包含Bean元数据的对象,它描述了如何创建Bean实例、Bean属性的值以及Bean之间的依赖关系,本文将带大家深入分析Spring BeanDefinition的构造元信息,需要的朋友可以参考下
    2024-01-01
  • kafka添加安全验证配置方式

    kafka添加安全验证配置方式

    这篇文章主要介绍了kafka添加安全验证配置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • Java中的拷贝数组CopyOnWriteArrayList详解

    Java中的拷贝数组CopyOnWriteArrayList详解

    这篇文章主要介绍了Java中的拷贝数组CopyOnWriteArrayList详解,ArrayList和LinkedList都不是线程安全的,如果需要线程安全的List,可以使用synchronizedList来生成一个同步list,但是这个同步list的方法都是通过synchronized修饰来保证同步的,需要的朋友可以参考下
    2023-12-12
  • Java如何根据word模板导出数据

    Java如何根据word模板导出数据

    这篇文章主要为大家详细介绍了Java如何实现根据word模板导出数据,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-05-05
  • Spring中存储Bean的常见注解方式

    Spring中存储Bean的常见注解方式

    Spring框架中的控制反转(IoC)和依赖注入(DI)是核心概念,实现了对象的解耦和动态依赖,IoC容器负责对象的生命周期和对象间的依赖关系,通过DI方式注入依赖,本文介绍Spring中存储Bean的常见注解方式,感兴趣的朋友一起看看吧
    2024-09-09
  • SpringBoot如何利用Twilio Verify发送验证码短信

    SpringBoot如何利用Twilio Verify发送验证码短信

    Twilio提供了一个名为 Twilio Verify 的服务,专门用于处理验证码的发送和验证,下面我们就来看看如何使用Twilio Verify实现发送验证码短信吧
    2025-03-03
  • Java获取当前时间方法总结

    Java获取当前时间方法总结

    本篇文章给大家整理了关于Java获取当前时间方法,以及相关代码分享,有需要的朋友测试参考下吧。
    2018-02-02

最新评论