Spring Boot 2.4.4自定义校验器注入Repository时JPA二次校验空指针问题
问题根因
Spring MVC层默认使用LocalValidatorFactoryBean作为校验入口,初始化自定义校验器时会关联Spring容器完成依赖注入,因此MVC触发的参数校验环节中注入的UserRepository可正常使用。
JPA层面的实体校验默认走Hibernate Validator自带的原生校验器工厂,这套原生逻辑完全不感知Spring容器的存在,创建自定义ConstraintValidator实例时只会直接调用类的无参构造器生成对象,完全跳过Spring的依赖注入流程,这就是JPA校验环节中Repository变为null、触发空指针的核心原因。
Spring Boot 2.4.4 适配解决方案
该版本无需调整原有校验器代码逻辑,仅需通过Spring Boot提供的JPA扩展点打通两层校验的容器关联即可:
- 新增JPA校验器配置类,通过
HibernatePropertiesCustomizer扩展点,将Spring托管的ValidatorFactory替换掉Hibernate原生的校验器工厂:
@Component public class SpringJpaValidatorCustomizer implements HibernatePropertiesCustomizer { @Autowired private ValidatorFactory springManagedValidatorFactory; @Override public void customize(Map<String, Object> hibernateProperties) { hibernateProperties.put("javax.persistence.ValidatorFactory", springManagedValidatorFactory); } }
这里注入的springManagedValidatorFactory就是MVC层正在使用的、和Spring容器打通的校验器工厂,它创建的所有自定义校验器实例都会自动完成Bean依赖注入。
- 删除临时关闭JPA校验的配置项
spring.jpa.properties.javax.persistence.validation.mode=none,恢复JPA层的实体校验能力。 - 原有
EmailValidator中的@Autowired UserRepository写法无需调整,无需手动编写静态工具类、属性反射赋值工具类等冗余逻辑。
注意:不要手动定义
EntityManagerFactoryBean覆盖Spring Boot的自动装配逻辑,否则会导致上述扩展点失效。
效果验证
- Controller层触发MVC参数校验时,通过Spring托管的ValidatorFactory生成
EmailValidator实例,注入的UserRepository可正常完成邮箱重复查询 - 调用
userRepository.save()触发JPA实体校验时,由于已经绑定了同一个Spring托管的ValidatorFactory,新生成的EmailValidator实例同样完成了UserRepository注入,不会再抛出NullPointerException
内容的提问来源于stack exchange,提问作者Sylvain
相关产品推荐
相关产品推荐

