依赖注入:如何避免向AccountValidator这类有状态对象隐藏依赖?
场景解决方案分析
一、可选应对方案
1. 工厂模式(原方案)
通过注入工厂类明确依赖,测试时可mock工厂返回自定义AccountValidator。缺点是会新增工厂类,但如果这类动态创建实例的场景不多,该方案逻辑清晰,维护成本可控。
2. 利用Spring内置的ObjectProvider/Provider
借助Spring原生的ObjectProvider(或JSR-330的Provider)延迟获取实例,无需手写工厂类,既能保持依赖注入的透明性,又能满足动态创建对象的需求。
3. 将AccountValidator设为原型Bean
把AccountValidator配置为原型作用域,每次获取都是新实例,结合构造参数注入实现Spring托管,同时适配有状态实例的创建需求。
4. 重构为无状态工具类
若业务逻辑允许,将AccountValidator改为无状态设计,把Account作为方法参数传入,直接注入单例Bean即可,这是最简洁的实现方式。
二、偏好方案
优先推荐无状态工具类改造(若业务允许),其次是原型Bean+ObjectProvider方案,原因如下:
- 避免额外工厂类的编写,减少类泛滥问题;
- 所有依赖通过构造注入声明,符合Spring最佳实践,单元测试时mock更便捷;
- 完全利用Spring容器能力,无需维护自定义逻辑。
三、将AccountValidator设为Spring托管的具体实现
情况1:业务允许改为无状态(推荐)
将AccountValidator改为无状态,校验逻辑通过方法参数接收Account,注册为单例Bean:
@Component class AccountValidator { public boolean isValid(Account account) { // 原校验逻辑,不再持有Account成员变量 ... } } // MyService直接注入AccountValidator @Component class MyService { private final AusiliaryService ausService; private final AccountValidator accountValidator; public MyService(AusiliaryService ausService, AccountValidator accountValidator) { this.ausService = ausService; this.accountValidator = accountValidator; } public boolean isAccountValid(Account account) { boolean isValid = accountValidator.isValid(account); if(isValid) { ausService.openAccount(account); } return isValid; } }
情况2:必须保持有状态(持有Account实例)
将AccountValidator设为原型作用域,通过ObjectProvider动态获取实例:
- 定义有状态的
AccountValidator:
class AccountValidator { private final Account account; public AccountValidator(Account account) { this.account = account; } public boolean isValid() { // 使用成员变量account执行校验 ... } }
- 在配置类中注册原型Bean:
@Configuration class AppConfig { @Bean @Scope("prototype") public AccountValidator accountValidator(Account account) { return new AccountValidator(account); } }
- MyService中注入
ObjectProvider获取实例:
@Component class MyService { private final AusiliaryService ausService; private final ObjectProvider<AccountValidator> accountValidatorProvider; public MyService(AusiliaryService ausService, ObjectProvider<AccountValidator> accountValidatorProvider) { this.ausService = ausService; this.accountValidatorProvider = accountValidatorProvider; } public boolean isAccountValid(Account account) { // 传入构造参数,获取原型实例 AccountValidator accountValidator = accountValidatorProvider.getObject(account); boolean isValid = accountValidator.isValid(); if(isValid) { ausService.openAccount(account); } return isValid; } }
内容的提问来源于stack exchange,提问作者GionJh
相关产品推荐
相关产品推荐

