一、多例(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 主导:
-
Spring 负责阶段:Bean 的创建(实例化)和初始化(如执行
@PostConstruct注解方法、实现 InitializingBean 接口的afterPropertiesSet()方法); -
Spring 不负责阶段:Bean 的销毁。多例 Bean 实例创建后,其生命周期控制权完全交给调用者,Spring 不会跟踪实例的引用状态,也不会主动触发销毁方法(如
@PreDestroy注解方法、实现 DisposableBean 接口的destroy()方法); -
最终回收:当多例 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)动态获取,确保每次获取的都是新实例。
测试场景使用建议
-
优先用于状态化测试组件:如测试用例的参数载体、测试数据上下文等,确保每个测试用例的状态独立;
-
避免多例 Bean 持有持久化资源:若必须持有,需在测试用例的
@After方法中手动释放资源; -
单例依赖多例时强制动态获取:在测试代码或被测试的单例 Bean 中,通过 ApplicationContext 动态获取多例 Bean,规避多例失效问题;
-
结合测试框架注解:在 Spring Boot 测试中,可通过
@SpringBootTest加载上下文后,在每个测试用例中通过@Autowired结合动态获取的方式使用多例 Bean,保障测试灵活性。