@Scope(“prototype“)

@Scope("prototype") 是 Spring 框架中用于定义 Bean 作用域的注解之一,它的主要作用是将一个 Bean 定义成 原型作用域Prototype Scope)。在原型作用域下,每次从 Spring 容器中请求这个 Bean 时,都会创建一个新的实例。


@Scope("prototype") 的作用

  1. 默认作用域:单例(Singleton Scope)

    在 Spring 中,Bean 的默认作用域是单例(@Scope("singleton")),意味着整个 Spring 容器中只会创建一个该 Bean 的实例,无论获取该 Bean 的次数有多少,都会返回同一个实例。

  2. 原型作用域(Prototype Scope)

    如果将 Bean 标记为 @Scope("prototype"),则表示该 Bean 是原型作用域。每次通过 Spring 容器获取这个 Bean 时,都会创建一个全新的实例,这与单例作用域的行为完全不同。


如何使用 @Scope("prototype")

java 复制代码
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype") // 标记为原型作用域
public class PrototypeBean {
    public PrototypeBean() {
        System.out.println("PrototypeBean instance created!");
    }
}

@Scope("prototype") 的生命周期

与单例作用域的 Bean 不同,原型作用域的 Bean 具有以下特点:

  1. 每次请求都会创建一个新实例

    • 无论通过调用 ApplicationContext#getBean() 方法,还是通过注入方式(例如通过 @Autowired)获取原型作用域的 Bean,每次都会创建一个全新的实例。
  2. 不受 Spring 容器的完全管理

    • Spring 容器只负责创建和返回原型作用域的 Bean,但不会对其进行后续的生命周期管理(例如,不会销毁它)。
    • 开发者需要负责清理(销毁)原型作用域的 Bean(如果需要)。
  3. 适用场景

    • 原型作用域适用于需要「短生命周期」的对象,或者需要生成多个实例的场景,例如:
      • 操作中需要临时创建对象(如一个用户操作的上下文)。
      • 在某些场景中,您需要一个特定的对象,每次使用时都需要是全新的(而不是共享的)。

对比 @Scope("singleton")@Scope("prototype")

特性 单例作用域(Singleton) 原型作用域(Prototype)
默认值
实例数量 Spring 容器中只有一个实例 每次请求都会创建一个新实例
实例管理 由 Spring 容器全权负责(包括初始化和销毁) 仅由 Spring 容器负责创建,不负责销毁
适用场景 适用于共享的全局对象(如服务类或工具类等) 适用于需要「短生命周期」或需要动态创建的对象

示例代码与行为分析

以下是一个完整示例,演示 @Scope("prototype") 的作用:

PrototypeBean 类
java 复制代码
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class PrototypeBean {
    public PrototypeBean() {
        System.out.println("PrototypeBean instance created!");
    }
}
SingletonBean 类
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class SingletonBean {

    @Autowired
    private PrototypeBean prototypeBean1;

    public void showPrototypeBean() {
        System.out.println("PrototypeBean instance: " + prototypeBean1);
    }
}
主方法
java 复制代码
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestApp {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext("com.example");

        // 第一次获取 SingletonBean
        SingletonBean singletonBean1 = context.getBean(SingletonBean.class);
        singletonBean1.showPrototypeBean();

        // 第二次获取 SingletonBean
        SingletonBean singletonBean2 = context.getBean(SingletonBean.class);
        singletonBean2.showPrototypeBean();

        // 手动获取 PrototypeBean
        PrototypeBean prototypeBean1 = context.getBean(PrototypeBean.class);
        PrototypeBean prototypeBean2 = context.getBean(PrototypeBean.class);

        System.out.println("PrototypeBean instances comparison: " + (prototypeBean1 == prototypeBean2)); // false
    }
}
输出结果
plaintext 复制代码
PrototypeBean instance created!
PrototypeBean instance: com.example.PrototypeBean@1a2b3c4
PrototypeBean instance: com.example.PrototypeBean@1a2b3c4
PrototypeBean instance created!
PrototypeBean instance created!
PrototypeBean instances comparison: false

分析:

  1. PrototypeBean 的实例在 Spring 容器初始化时并未被创建(不同于单例作用域)。
  2. 每次调用 context.getBean(PrototypeBean.class) 时都会创建一个新实例。
  3. 如果将一个原型作用域的 Bean 注入到单例作用域的 Bean 中,Spring 容器只会注入 一个实例(因为依赖注入通常发生在容器启动时),后续不会动态更新。

在原型作用域中动态获取实例

如果您需要在运行时动态获取新的原型实例,可以通过以下方式解决:

  1. 使用 @Lookup 注解

    在单例作用域的 Bean 中通过 @Lookup 动态注入原型实例(如之前的例子)。

  2. 手动调用 ApplicationContext#getBean()

    手动从容器中获取新的原型实例。

  3. 使用 ObjectFactoryProvider

    通过 ObjectFactoryjavax.inject.Provider 提供动态获取实例的能力。

示例(使用 ObjectFactory):

java 复制代码
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class SingletonBean {

    @Autowired
    private ObjectFactory<PrototypeBean> prototypeBeanFactory;

    public void showPrototypeBean() {
        PrototypeBean prototypeBean = prototypeBeanFactory.getObject(); // 获取一个新的 PrototypeBean 实例
        System.out.println("PrototypeBean instance: " + prototypeBean);
    }
}

总结

  • @Scope("prototype") 意味着每次请求都会创建一个新的 Bean 实例。
  • 原型作用域适用于需要动态创建、短生命周期的对象。
  • 需要注意的是,Spring 容器不会完全管理原型作用域的 Bean,销毁和清理需要开发者自行处理。
相关推荐
韦禾水14 分钟前
记录一次项目部署到tomcat的异常
java·tomcat
曦月合一23 分钟前
树莓派安装jdk、tomcat、vnc、谷歌浏览器开机自启等环境配置
java·tomcat·树莓派
harder32136 分钟前
RMP模式的创新突破
开发语言·学习·ios·swift·策略模式
jinanwuhuaguo1 小时前
OpenClaw工程解剖——RAG、向量织构与“记忆宫殿”的索引拓扑学(第十三篇)
android·开发语言·人工智能·kotlin·拓扑学·openclaw
Rust研习社1 小时前
使用 Axum 构建高性能异步 Web 服务
开发语言·前端·网络·后端·http·rust
此剑之势丶愈斩愈烈1 小时前
openssl 自建证书
java
面汤放盐1 小时前
何时使用以及何时不应使用微服务:没有银弹
java·运维·云计算
0xDevNull1 小时前
Spring Boot 自动装配:从原理到实践
java·spring boot·后端
qq_589568102 小时前
java学习笔记,包括idea快捷键
java·ide·intellij-idea
淘矿人3 小时前
从0到1:用Claude启动你的第一个项目
开发语言·人工智能·git·python·github·php·pygame