自定义ConstraintValidator校验器无法Autowired注入Bean如何解决
问题根因
默认Hibernate Validator创建自定义校验器实例时,会直接通过反射调用类的无参构造方法完成实例化,不会经过Spring IOC容器。你当前的自定义校验器仅定义了带MyService参数的构造方法,未提供无参构造,因此直接抛出java.lang.NoSuchMethodException: <init>()异常;同时由于实例不是Spring容器管理的,@Autowired注解也不会生效。
解决方案(推荐)
通过配置将校验器的实例化交给Spring容器管理,即可支持依赖注入。
步骤1:配置Spring校验工厂
新增校验配置类,指定使用Spring提供的校验器工厂来创建校验器实例:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.validation.beanvalidation.SpringConstraintValidatorFactory; import javax.validation.Validator; @Configuration public class ValidationConfig { @Bean public Validator validator(SpringConstraintValidatorFactory springConstraintValidatorFactory) { LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean(); factoryBean.setConstraintValidatorFactory(springConstraintValidatorFactory); return factoryBean; } }
步骤2:修改自定义校验器
给校验器添加@Component注解,将其纳入Spring容器管理,直接使用构造注入即可:
@Slf4j @Component @RequiredArgsConstructor // 无需手动写构造方法,Lombok会生成带final属性的构造函数 public class MyValidator implements ConstraintValidator<ValidMapper, String> { private final MyService myService; @Override public boolean isValid(String valueToValid, ConstraintValidatorContext context) { // 直接使用注入的myService执行业务逻辑即可 return true; } }
备选方案(手动获取Bean)
如果不想调整全局校验配置,可以通过Spring上下文工具类手动获取业务Bean:
步骤1:实现Spring上下文工具类
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class SpringContextHolder implements ApplicationContextAware { private static ApplicationContext CONTEXT; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { CONTEXT = applicationContext; } public static <T> T getBean(Class<T> beanClass) { return CONTEXT.getBean(beanClass); } }
步骤2:在校验器初始化时获取Bean
@Slf4j public class MyValidator implements ConstraintValidator<ValidMapper, String> { private MyService myService; @Override public void initialize(ValidMapper constraintAnnotation) { // 初始化时手动从Spring上下文获取业务Bean this.myService = SpringContextHolder.getBean(MyService.class); } @Override public boolean isValid(String valueToValid, ConstraintValidatorContext context) { // 正常使用myService即可 return true; } }
内容的提问来源于stack exchange,提问作者Rio85
相关产品推荐
相关产品推荐

