SpringBean的生命周期-SpringBean的作用域以及注解使用-《Java笔记》

admin 2025-10-19 04:25:53 编程 来源:ZONE.CI 全球网 0 阅读模式

Java Spring

Spring Bean的作用域

Spring Bean 的作用域即为对象的作用范围。Spring Bean的作用域由配置项 scope 来限定。

Scope配置项

作用域限定了 Spring Bean 的作用范围,在 Spring 配置文件定义 Bean 时,通过声明 scope 配置项,可以灵活定义 Bean 的作用范围。想要容器创建的 bean 为单例模式,就设置 Scope 为 singleton;想要每次创建的 bean 都是不同的对象则使用 prototype

六大作用域

官方文档给出的bean作用域的简单介绍。image.gif文档的表格写着是六个作用域,但是很多时候都会被认为只有五个作用域。因为 applicationwebsocket 的作用差不多。所以会被认为是一个。

范围 描述
singleton (默认)将每个Spring IoC容器的单个 bean 定义范围限定为单个对象实例。
prototype 将单个 bean 定义的作用域限定为任意数量的对象实例。
request 将单个 bean 定义的范围限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有一个自己的 bean 实例,它是在单个 bean 定义的后面创建的。仅在可感知网络的 Spring 上下文中有效 ApplicationContext
session 将单个 bean 定义的范围限定为 HTTP 的生命周期 Session。仅在可感知网络的 Spring 上下文中有效 ApplicationContext
application 将单个 bean 定义的作用域限定为的生命周期 ServletContext。仅在可感知网络的Spring上下文中有效 ApplicationContext
websocket 将单个 bean 定义的作用域限定为的生命周期 WebSocket。仅在可感知网络的Spring上下文中有效 ApplicationContext

重点放在 singleton 和 prototype ,后面四个是对于WebMVC而言的,暂不进行详细阐述。

单例作用域

先看第一个单例范围,单例范围即无论使用多少个 Dao 去获取 bean ,每次获取到的都是一个相同的 bean对象。Spring Bean的作用域以及注解使用 - 图2「singleton」 与所说的单例模式基本是相同的,singleton 也是默认的作用域,如果没用指定 bean 对象的作用域则在整个上下文环境中通过 Spring IOC 获取到的 bean 都是同一个实例。配置 bean 为 singleton 作用域代码:

  1. <bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>

接下来定义一个POJO类 — User来演示 scope 属性对实例的影响。

  1. public class User {
  2. private String name;
  3. private int age;
  4. public User() {
  5. }
  6. public User(String name, int age) {
  7. this.name = name;
  8. this.age = age;
  9. }
  10. /*toString和getter/setter*/
  11. @Override
  12. public String toString() {
  13. return "User{" +
  14. "name='" + name + '\'' +
  15. ", age=" + age +
  16. '}';
  17. }
  18. public String getName() {
  19. return name;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. public int getAge() {
  25. return age;
  26. }
  27. public void setAge(int age) {
  28. this.age = age;
  29. }
  30. }

再显示的把该 bean 的作用域设置为 singleton。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:p="http://www.springframework.org/schema/p"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. https://www.springframework.org/schema/beans/spring-beans.xsd ">
  7. <bean id="user" class="com.javastudyway.pojo.User" p:name="Hello" p:age="4" scope="singleton"/>
  8. </beans>

最后就是测试类了:

  1. import com.javastudyway.pojo.Student;
  2. import com.javastudyway.pojo.User;
  3. import org.junit.Test;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;
  6. public class MyTest {
  7. @Test
  8. public void testSingleton(){
  9. ApplicationContext context = new ClassPathXmlApplicationContext("userbean.xml");
  10. User user1 = context.getBean("user",User.class);
  11. User user2 = context.getBean("user",User.class);
  12. System.out.println(user1 == user2);
  13. }
  14. }

测试结果如下:从比较结果可以看出,程序两次从 IOC 容器中获取的 User 实例「地址比较结果相同」,说明 IOC 容器返回的是「同一个实例」Spring Bean的作用域以及注解使用 - 图3

原型作用域

与 singleton 刚好相反,prototype,是程序每次从 IOC 容器获取的 Bean 都是一个新的实例。这次把 bean 的配置修改成 「prototype」,再进行测试。

  1. <bean id="user" class="com.javastudyway.pojo.User" p:name="Java学习之道" p:age="4" scope="prototype"/>

在测试类中增加一个测试方法:

  1. @Test
  2. public void testPrototype(){
  3. ApplicationContext context = new ClassPathXmlApplicationContext("userbean.xml");
  4. User user1 = context.getBean("user", User.class);
  5. User user2 = context.getBean("user", User.class);
  6. System.out.println("两次对象地址比较结果为:" + (user1 == user2));
  7. System.out.println("user1 的hasCode为:" + user1.hashCode());
  8. System.out.println("user2 的hasCode为:" + user2.hashCode());
  9. }

测试结果为:Spring Bean的作用域以及注解使用 - 图4可以看到,程序两次从 IOC 容器中获取的 user1 和 user2 实例的 hashCode 不相同,说明 User 添加 prototype 作用域后,IOC 容器每次返回的都是一个新的实例。对于作用域使用场景的总结:

有状态的bean应该使用prototype作用域; 对无状态的bean则应该使用singleton作用域。

使用注解声明bean的作用域

大多数时候都不想很麻烦的去修改 applicationContext.xml ,所以可以使用注解来配置 bean 的作用范围。具体步骤为

  • 使用 **@Component** 注解将 POJO 类声明为一个 bean;
  • 使用 **@Scope** 注解声明 bean 的作用域;
  • 修改 「applicationContext.xml」 开启扫描 POJO 包中的所有类的注解。

    修改POJO类

    在 POJO 类上增加 @Component,让 Spring 将 User 视为一个 bean。在 POJO 类上增加 @Scope 注解,标识该 bean 的作用域为 singleton。
    1. import org.springframework.context.annotation.Scope;
    2. import org.springframework.stereotype.Component;
    3. @Component("user")
    4. @Scope("singleton")
    5. public class User {
    6. private String name;
    7. private int age;
    8. public User() {
    9. }
    10. public User(String name, int age) {
    11. this.name = name;
    12. this.age = age;
    13. }
    14. @Override
    15. public String toString() {
    16. return "User{" +
    17. "name='" + name + '\'' +
    18. ", age=" + age +
    19. '}';
    20. }
    21. public String getName() {
    22. return name;
    23. }
    24. public void setName(String name) {
    25. this.name = name;
    26. }
    27. public int getAge() {
    28. return age;
    29. }
    30. public void setAge(int age) {
    31. this.age = age;
    32. }
    33. }

    开启注解扫描

    增加完注解后只需要对 applicationContext.xml 这个 Spring 的配置文件做上一小部分修改,即可实现注解开发了。开启 com.javastudyway.pojo 包中的所有类的注解扫描。
    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xmlns:p="http://www.springframework.org/schema/p"
    6. xmlns:c="http://www.springframework.org/schema/c"
    7. xsi:schemaLocation="http://www.springframework.org/schema/beans
    8. https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    9. <!-- 开启注解扫描 -->
    10. <context:component-scan base-package="com.javastudyway.pojo"/>
    11. </beans>

    测试

    对 POJO 类加上注解和开启注解扫描后,就可以通过简单的注解来设置 bean 的作用域而不再需要去配置文件中慢慢修找修改了。用刚刚 测试原型作用域的方法 来测试用注解修改成 singleton 的 bean。Spring Bean的作用域以及注解使用 - 图5结果从原来的 「false,hashCode 不相等」变成了 「true,hashCode 相等」了。
以太坊cppgolang区别 编程

以太坊cppgolang区别

以太坊是一种去中心化的开源平台,它采用智能合约技术,旨在构建和运行不受干扰的分布式应用程序。作为目前最受欢迎的区块链平台之一,以太坊提供了多种编程语言的支持,其
progolang 编程

progolang

Go语言(Golang)是由Google开发的一门静态类型编程语言。作为一名专业的Golang开发者,我深知这门语言的优势和特点。在本文中,我将介绍Golang
golangn个发送者 编程

golangn个发送者

Golang是一种开源的编程语言,由Google团队开发,旨在提高程序的并发性和简化软件开发过程。在Go语言中,有时需要向多个接收者发送信息。本文将介绍如何在G
golang技能图谱 编程

golang技能图谱

从互联网行业的快速发展到人工智能技术的日益成熟,各种编程语言也应运而生。而在这众多的编程语言中,Golang(即Go)作为一门强大且高效的开发语言备受关注。Go
评论:0   参与:  14