You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法将服务注入ConstraintValidator:HV000064异常排查与解决

问题描述

自定义ConstraintValidator委托EntryService校验LocalDate合法性,该校验器应用在@Entity字段上,期望在Hibernate生命周期事件(如持久化、删除前)执行校验,但抛出异常:

jakarta.validation.ValidationException: HV000064: Unable to instantiate ConstraintValidator: x.xx.xxx.util.validator.DateIsOpenValidator

校验器初始实现代码:

@RequiredArgsConstructor
public class DateIsOpenValidator implements ConstraintValidator<DateIsOpen, LocalDate> {
  private final EntryService entryService;

  @Override
  public boolean isValid(LocalDate date, ConstraintValidatorContext context) {
    return entryService.validateDateIsOpen(date);
  }
}

已尝试的方案:

  • 配置LocalValidatorFactoryBean作为默认Validator Bean:
@Bean
public LocalValidatorFactoryBean validator() {
    return new LocalValidatorFactoryBean();
}
  • 为校验器添加无参构造,但导致EntryService为null:
public class DateIsOpenValidator implements ConstraintValidator<DateIsOpen, LocalDate> {

    private EntryService entryService;

    public DateIsOpenValidator() {}

    public DateIsOpenValidator(EntryService entryService) {
        this.entryService = entryService;
    }

    @Override
    public boolean isValid(LocalDate date, ConstraintValidatorContext context) {
        if (entryService == null) {
            throw new IllegalStateException("EntryService has not been initialized");
        }
        return entryService.validateDateIsOpen(date);
    }
}
  • 配置HibernatePropertiesCustomizer指定校验器:
@Bean
@Lazy
public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(final Validator validator) {
    return hibernateProperties -> 
        hibernateProperties.put("jakarta.persistence.validation.factory", validator);
}

现象:仅配置LocalValidatorFactoryBean无法解决问题;添加无参构造规避实例化异常但依赖无法注入;当前配置表面可行但怀疑遗漏步骤,询问如何正确注入EntryService到ConstraintValidator。

正确实现步骤

1. 让校验器被Spring容器管理

给DateIsOpenValidator添加@Component注解,确保Spring能扫描并管理该类,这是依赖注入生效的前提:

@Component
@RequiredArgsConstructor
public class DateIsOpenValidator implements ConstraintValidator<DateIsOpen, LocalDate> {
  private final EntryService entryService;

  @Override
  public boolean isValid(LocalDate date, ConstraintValidatorContext context) {
    return entryService.validateDateIsOpen(date);
  }
}

若校验器不在Spring默认组件扫描路径下,需手动通过@Bean将其注册到容器中。

2. 正确配置LocalValidatorFactoryBean

需要让LocalValidatorFactoryBean使用Spring的AutowireCapableBeanFactory创建校验器实例,以此支持依赖注入。修改Validator配置:

@Bean
public LocalValidatorFactoryBean validator(AutowireCapableBeanFactory beanFactory) {
    LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
    validator.setConstraintValidatorFactory(new SpringConstraintValidatorFactory(beanFactory));
    return validator;
}

3. 修正HibernatePropertiesCustomizer配置

确保Hibernate使用Spring提供的Validator实例,修正原配置的语法问题:

@Bean
@Lazy
public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(Validator validator) {
    return hibernateProperties -> 
        hibernateProperties.put("jakarta.persistence.validation.factory", validator);
}

4. 确认校验注解的正确性

确保@DateIsOpen注解指定了正确的校验器类:

@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
@Constraint(validatedBy = DateIsOpenValidator.class)
public @interface DateIsOpen {
    String message() default "日期不合法";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

关键注意事项

  • 无需给校验器添加无参构造,@RequiredArgsConstructor生成的带参构造会被Spring用来完成依赖注入,前提是校验器已被Spring管理。
  • 确保EntryService是Spring管理的Bean(如添加了@Service注解),否则无法被注入到校验器中。
  • Spring Boot默认会自动配置LocalValidatorFactoryBean,但如果自定义了Validator Bean,必须确保配置正确关联Spring的Bean工厂。

内容的提问来源于stack exchange,提问作者Jasper Lutz Severino

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 07:08:23