Spring如何自动注入CreditValidations所有实现?手动注入方式是否合理?
问题解答
一、当前依赖注入方式的合理性分析
你当前手动通过Arrays.asList(new ValidateAge(), new ValidateSalary())初始化校验列表的方式不合理,核心问题包括:
- 硬编码依赖违反开闭原则:新增校验规则时必须修改
ValidationUtils构造方法,易引发人为错误 - 无法利用Spring IoC容器特性:比如依赖管理、AOP增强、Bean生命周期管理等能力被浪费
- 职责耦合:
ValidationUtils同时承担校验逻辑调度和实例创建职责,不符合单一职责原则
二、Spring自动注入所有CreditValidations实现的方案
Spring完全支持自动收集并注入所有CreditValidations类型的Bean,具体步骤如下:
1. 标记校验类为Spring组件
给所有CreditValidations的实现类添加@Component注解(或@Service等同类注解):
@Component public class ValidateAge extends CreditValidations { public ValidateAge() { super(CreditValidationErrorEnum.ERROR_VALIDATING_AGE.getCode()); } @Override public boolean validate(final Client client, List<String> validationsFailed) { return this.evaluateValidation(client.getAge() >= 18, validationsFailed); } } // ValidateSalary同理添加@Component注解
2. 修改ValidationUtils构造方法注入
将ValidationUtils标记为Spring组件,并通过构造方法注入List<CreditValidations>:
@Component public class ValidationUtils { private final List<CreditValidations> creditValidations; // Spring会自动扫描并注入所有CreditValidations类型的Bean public ValidationUtils(List<CreditValidations> creditValidations) { this.creditValidations = creditValidations; } public ValidationRs passAllValidations(Client client){ final var validationsFailed = new ArrayList<String>(); // 修正原逻辑错误:原Boolean.logicalXor无法正确判断"所有校验通过",改用逻辑与 boolean allValid = true; for (CreditValidations validation : creditValidations){ boolean isValid = validation.validate(client, validationsFailed); allValid = allValid && isValid; } final var rs = new ValidationRs(); rs.setSuccessfulValidations(allValid); rs.setValidationsFailed(validationsFailed); return rs; } }
3. 可选:控制校验执行顺序
如果需要指定校验规则的执行顺序,给每个校验类添加@Order注解:
@Order(1) // 数值越小,执行优先级越高 @Component public class ValidateAge extends CreditValidations { // ... } @Order(2) @Component public class ValidateSalary extends CreditValidations { // ... }
三、设计模式优化建议
你的实现已经具备策略模式的雏形(每个校验规则是一个独立策略),可以进一步优化:
1. 将抽象类改为接口
用接口替代抽象类CreditValidations,更符合面向接口编程原则,提升灵活性:
public interface CreditValidation { boolean validate(Client client, List<String> validationsFailed); } // 保留抽象基类封装通用逻辑(可选) public abstract class AbstractCreditValidation implements CreditValidation { protected final String errorCode; protected AbstractCreditValidation(final String errorCode) { this.errorCode = errorCode; } protected boolean evaluateValidation(boolean validationResult, List<String> validationsFailed){ if (!validationResult){ validationsFailed.add(errorCode); } return validationResult; } } // 校验类实现接口 @Component public class ValidateAge extends AbstractCreditValidation implements CreditValidation { // ... }
2. 结合Spring Validator生态
如果场景允许,可以对齐Spring自带的org.springframework.validation.Validator接口,复用Spring校验框架能力,比如配合@Valid注解、全局校验器等,减少自定义代码量。
3. 分组校验扩展
如果需要针对不同业务场景使用不同校验规则,可以通过自定义注解+@Qualifier实现分组注入:
- 定义分组注解(如
@BasicCheck、@AdvancedCheck) - 给校验类添加对应的
@Qualifier注解 - 注入时通过
@Qualifier筛选对应分组的校验规则
内容的提问来源于stack exchange,提问作者Dazt
相关产品推荐
相关产品推荐

