Spring框架中 Bean 的 prototype 作用域

举报
幼儿园老大* 发表于 2025/01/24 16:30:17 2025/01/24
160 0 0
【摘要】 ​在 Spring 框架中,prototype 是 Bean 的作用域(Scope)之一。它表示每次从 Spring 容器中获取该 Bean 时,都会创建一个新的实例。这与默认的 singleton 作用域不同,singleton 作用域下,Spring 容器中只会存在一个 Bean 实例。1. prototype 作用域的特点每次请求都会创建新实例:每次通过 ApplicationCont...

在 Spring 框架中,prototype 是 Bean 的作用域(Scope)之一。它表示每次从 Spring 容器中获取该 Bean 时,都会创建一个新的实例。这与默认的 singleton 作用域不同,singleton 作用域下,Spring 容器中只会存在一个 Bean 实例。


1. prototype 作用域的特点

  • 每次请求都会创建新实例:每次通过 ApplicationContext.getBean() 或依赖注入获取 Bean 时,都会创建一个新的实例。

  • 生命周期不由 Spring 管理prototype Bean 的初始化回调(如 @PostConstruct)会执行,但销毁回调(如 @PreDestroy)不会执行,因为 Spring 不会管理 prototype Bean 的生命周期。

  • 适合有状态的 Bean:如果 Bean 需要维护状态,或者每次使用时需要独立的实例,可以使用 prototype 作用域。


2. 配置 prototype 作用域

可以通过以下方式配置 prototype 作用域:

2.1 使用注解

在类上使用 @Scope 注解:

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype") // 指定作用域为 prototype
public class MyPrototypeBean {
    public MyPrototypeBean() {
        System.out.println("MyPrototypeBean created!");
    }
}

2.2 使用 XML 配置

在 XML 配置文件中定义 Bean 时指定 scope 属性:

<bean id="myPrototypeBean" class="com.example.MyPrototypeBean" scope="prototype"/>

运行 HTML


3. 使用 prototype Bean

在 Spring 中,prototype Bean 的使用方式与 singleton Bean 相同,但每次获取时都会创建一个新实例。

3.1 通过依赖注入

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyService {

    private final MyPrototypeBean prototypeBean;

    @Autowired
    public MyService(MyPrototypeBean prototypeBean) {
        this.prototypeBean = prototypeBean;
        System.out.println("MyService created with prototypeBean: " + prototypeBean);
    }
}

3.2 通过 ApplicationContext 获取

import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class MyService {

    private final ApplicationContext context;

    public MyService(ApplicationContext context) {
        this.context = context;
    }

    public void usePrototypeBean() {
        MyPrototypeBean bean1 = context.getBean(MyPrototypeBean.class);
        MyPrototypeBean bean2 = context.getBean(MyPrototypeBean.class);
        System.out.println("bean1 == bean2: " + (bean1 == bean2)); // false
    }
}

4. prototype 与 singleton 的区别

特性 prototype singleton
实例数量 每次请求创建一个新实例 整个容器中只有一个实例
生命周期管理 Spring 不管理销毁阶段 Spring 管理完整的生命周期
适用场景 有状态的 Bean,需要独立实例的场景 无状态的 Bean,共享实例的场景
性能 每次请求都会创建新实例,性能较低 单例模式,性能较高

5. 注意事项

  • prototype Bean 注入到 singleton Bean 中

    • 如果 prototype Bean 被注入到 singleton Bean 中,prototype Bean 的行为仍然是单例的,因为 singleton Bean 只会初始化一次。

    • 解决方法:使用 @Lookup 注解或 Provider 接口。

5.1 使用 @Lookup 注解

import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.stereotype.Component;

@Component
public abstract class MyService {

    @Lookup
    public abstract MyPrototypeBean getPrototypeBean();

    public void usePrototypeBean() {
        MyPrototypeBean bean1 = getPrototypeBean();
        MyPrototypeBean bean2 = getPrototypeBean();
        System.out.println("bean1 == bean2: " + (bean1 == bean2)); // false
    }
}

5.2 使用 Provider 接口

import javax.inject.Provider;
import org.springframework.stereotype.Component;

@Component
public class MyService {

    private final Provider<MyPrototypeBean> prototypeBeanProvider;

    public MyService(Provider<MyPrototypeBean> prototypeBeanProvider) {
        this.prototypeBeanProvider = prototypeBeanProvider;
    }

    public void usePrototypeBean() {
        MyPrototypeBean bean1 = prototypeBeanProvider.get();
        MyPrototypeBean bean2 = prototypeBeanProvider.get();
        System.out.println("bean1 == bean2: " + (bean1 == bean2)); // false
    }
}

6. 总结

  • prototype 作用域适用于需要每次创建新实例的场景。

  • 通过 @Scope("prototype") 或 XML 配置可以定义 prototype Bean。

  • 注意 prototype Bean 注入到 singleton Bean 中的问题,可以使用 @Lookup 或 Provider 解决。


【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。