多例(prototype)Bean

一、多例(prototype)Bean 的创建时机

多例 Bean 不存在"预初始化"行为,其创建时机严格遵循"按需创建"原则,即每次通过 Spring 容器获取 Bean 时才会创建新的实例,具体触发场景包括:

  • 主动获取:通过 Spring 上下文(ApplicationContext)的 context.getBean(BeanClass.class)context.getBean("beanName") 方法主动获取时,创建新实例;

  • 依赖注入:当其他 Bean(单例或多例)依赖该多例 Bean 时,注入过程中会创建新实例(注:单例 Bean 依赖多例 Bean 时存在特殊问题,详见下文)。

测试场景价值:该特性确保每个测试用例获取的多例 Bean 都是全新的、无历史状态的实例,避免前一个测试用例的操作影响后一个测试用例的结果(如测试用例1修改了 Bean 的成员变量,测试用例2获取新实例可避免受该修改影响)。

二、多例(prototype)Bean 的生命周期特点

与单例 Bean 不同,多例 Bean 的生命周期管理具有"不完整"特性,Spring 仅负责前两个阶段,后续阶段由调用者和 GC 主导:

  1. Spring 负责阶段:Bean 的创建(实例化)和初始化(如执行 @PostConstruct 注解方法、实现 InitializingBean 接口的 afterPropertiesSet() 方法);

  2. Spring 不负责阶段:Bean 的销毁。多例 Bean 实例创建后,其生命周期控制权完全交给调用者,Spring 不会跟踪实例的引用状态,也不会主动触发销毁方法(如 @PreDestroy 注解方法、实现 DisposableBean 接口的 destroy() 方法);

  3. 最终回收:当多例 Bean 实例不再被任何对象引用时,由 JVM 的垃圾回收器(GC)自动回收,释放内存资源。

测试场景注意:若多例 Bean 持有资源(如数据库连接、文件流),测试完成后需手动调用自定义的资源释放方法,避免资源泄露影响测试环境稳定性。

三、测试场景核心注意:依赖注入的特殊规则

测试场景中,多例 Bean 与单例 Bean 的依赖注入存在明确的规则差异,若误用会导致测试结果异常,需重点关注

1. 多例 Bean 中注入单例 Bean:允许且正常生效

多例 Bean 中注入单例 Bean 是完全合法的,且符合预期:单例 Bean 由 Spring 容器全局管理,仅存在一个实例,该实例会被所有多例 Bean 共享。

测试场景示例:多个测试用例对应的多例测试 Bean 注入同一个单例的数据源 Bean,确保所有测试用例使用相同的数据源连接,保障测试环境的一致性。

2. 单例 Bean 中注入多例 Bean:存在失效问题,需特殊处理

这是测试场景中最易踩坑的点:单例 Bean 仅在容器启动时初始化一次,初始化过程中会注入依赖的多例 Bean------此时注入的是第一次创建的多例 Bean 实例,后续单例 Bean 复用过程中,不会再次创建新的多例实例,导致多例 Bean 失去"每次获取均为新实例"的特性,即"多例失效"。

测试场景影响:若测试用例依赖的单例 Bean 内部持有多例 Bean,多个测试用例会共享同一个多例 Bean 实例,出现测试用例间的状态干扰,导致测试结果不准确。

解决方案:在单例 Bean 中通过 Spring 上下文(ApplicationContext)动态获取多例 Bean,而非直接依赖注入。具体实现方式:

  • 让单例 Bean 实现 ApplicationContextAware 接口,通过重写 setApplicationContext(ApplicationContext context) 方法获取上下文;

  • 每次需要使用多例 Bean 时,通过context.getBean(PrototypeBean.class) 动态获取,确保每次获取的都是新实例。

测试场景使用建议

  1. 优先用于状态化测试组件:如测试用例的参数载体、测试数据上下文等,确保每个测试用例的状态独立;

  2. 避免多例 Bean 持有持久化资源:若必须持有,需在测试用例的 @After方法中手动释放资源;

  3. 单例依赖多例时强制动态获取:在测试代码或被测试的单例 Bean 中,通过 ApplicationContext 动态获取多例 Bean,规避多例失效问题;

  4. 结合测试框架注解:在 Spring Boot 测试中,可通过 @SpringBootTest 加载上下文后,在每个测试用例中通过 @Autowired 结合动态获取的方式使用多例 Bean,保障测试灵活性。

相关推荐
Amumu121382 天前
Js: 构造函数、继承、面向对象
原型模式
砍光二叉树3 天前
【设计模式】创建型-原型模式
设计模式·原型模式
RFCEO4 天前
JavaScript基础课程十四、原型与原型链(JS 核心底层)
开发语言·原型模式·prototype原型详解·javascript基础课·构造函数原型方法定义与使用·js原型链继承机制入门·t原型链顶层null原理
new code Boy5 天前
前端核心基础汇总
开发语言·javascript·原型模式
爱写bug的野原新之助5 天前
爬虫之补环境脚本:脱环境
javascript·爬虫·原型模式
承缘丶7 天前
使用http调用Kettle资源库中的ETL任务
原型模式
夕珩10 天前
单例模式、原型模式、工厂方法模式、抽象工厂模式、建造者模式、解释器模式、命令模式
单例模式·解释器模式·建造者模式·工厂方法模式·抽象工厂模式·命令模式·原型模式
TON_G-T12 天前
JavaScript 原型与原型链
开发语言·javascript·原型模式
蜜獾云12 天前
设计模式之原型模式:以自己为原型,自己实现自己的对象拷贝逻辑
java·设计模式·原型模式
geovindu12 天前
python: Prototype Pattern
python·设计模式·原型模式