Spring框架中 Bean 的 prototype 作用域

Spring框架中 Bean 的 prototype 作用域

在 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 属性:

运行 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 prototypeBeanProvider;

public MyService(Provider 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 解决。

相关推荐

Ubuntu 20.04 启动时等待网络配置时间过久问题的解决方法
beat365平台正版

Ubuntu 20.04 启动时等待网络配置时间过久问题的解决方法

📅 07-05 👁️ 2424
硬盘坏道如何屏蔽?最全攻略都在这了!
365bet线上网址

硬盘坏道如何屏蔽?最全攻略都在这了!

📅 08-10 👁️ 3972
《DNF》竹子怎么升级
beat365平台正版

《DNF》竹子怎么升级

📅 08-06 👁️ 4978