自动连接在自定义约束验证程序中给出 Null 值

我对Spring完全陌生,我已经在SO上寻找了一些关于所提问题的答案。以下是链接:

Spring 3.1 自动布线在自定义约束验证程序中不起作用

将服务自动连接到验证程序

自动连接的存储库在自定义约束验证程序中为 Null

我有一个Spring项目,我想使用Hibernate Validator进行对象验证。根据我在网上阅读的内容和一些论坛,我试图注入验证器,如下所示:

@Bean
  public Validator validator() {
    return new LocalValidatorFactoryBean().getValidator();
  }

但是无论我在哪里使用

@Autowired
Validator validator;

它采用Spring的验证器实现,而不是Hibernate的验证器。我无法弄清楚如何准确地注入Hibernate验证器,并简单地将其自动连接到其他类中,所以我使用了一个便宜的技巧,现在我的Java配置看起来像这样

@Bean
      public Validator validator() {
        // ValidatorImpl is Hibernate's implementation of the Validator
        return new ValidatorImpl();
      }

(如果有人真的能为我指出正确的方向,如何避免以这种Hacky的方式获得Hibernate Validator,我将不胜感激。)

但是,让我们来看看这里的主要问题:

下面是自定义验证定义

@Target( { METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER } )
@Retention(RUNTIME)
@Constraint(validatedBy = EmployeeValidator.class)
@Documented
public @interface EmployeeValidation {
String message() default "{constraints.employeeConstraints}";
public abstract Class<?>[] groups() default {};
public abstract Class<? extends Payload>[] payload() default {};
}

我的自定义验证器

public class EmployeeValidator implements ConstraintValidator<EmployeeValidation , Object> {

@Autowired
private EmployeeService employeeService;

@Override
public void initialize(EmployeeValidation constraintAnnotation) {
//do Something
 }

@Override
public boolean isValid(String type, ConstraintValidatorContext context) {
    return false;
}
}

在上面的自定义约束验证程序中,我得到员工服务空。我知道当Spring启动时,ConstraintValidator的任何实现都不会实例化,但我认为添加ValidatorImpl()实际上会解决这个问题。但事实并非如此。

现在我陷入了一个非常黑客的解决方法,我不想继续这样的代码。有人可以帮助我解决我的情况吗?

附言:这些是我在Java配置文件中的导入:

import org.hibernate.validator.HibernateValidator; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.context.MessageSource; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.ComponentScan; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.context.annotation.PropertySource; 
import org.springframework.context.support.ReloadableResourceBundleMessageSource; 
import org.springframework.core.env.Environment; 
import org.springframework.validation.Validator; 
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; 
import org.springframework.web.servlet.LocaleResolver; 
import org.springframework.web.servlet.ViewResolver; 
import org.springframework.web.servlet.config.annotation.EnableWebMvc; 
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; 
import org.springframework.web.servlet.i18n.CookieLocaleResolver; 
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; 
import org.springframework.web.servlet.view.InternalResourceViewResolver; 

答案 1

我希望这个解决方案能帮助别人:

@Bean
public Validator validator () {

    ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
        .configure().constraintValidatorFactory(new SpringConstraintValidatorFactory(autowireCapableBeanFactory))
        .buildValidatorFactory();
    Validator validator = validatorFactory.getValidator();

    return validator;
}

初始化验证程序,以便注入工作,并提供验证程序实现为休眠.class按以下方式工作:SpringConstraintValidatorFactory

  1. 您的对象将由您选择的库进行验证
  2. 您的自定义验证器将能够使用Spring的功能,同时由Hibernate执行验证。

它是如何工作的:Hibernate's不会初始化任何,除非它们被调用,但通过给它来初始化。ConstraintValidatorFactoryConstraintValidatorsSpringConstraintValidatorFactoryAutowireCapableBeanFactory

编辑

正如@shabyasaschi的注释之一中提到的,要注入,您可以将方法签名更改为:autowireCapableBeanFactory

Validator validator(final AutowireCapableBeanFactory autowireCapableBeanFactory) {

或在配置文件中为其添加 getter 和 setter,如下所示:

public AutowireCapableBeanFactory getAutowireCapableBeanFactory() {
        return autowireCapableBeanFactory;
}

public void setAutowireCapableBeanFactory(AutowireCapableBeanFactory autowireCapableBeanFactory) {
        this.autowireCapableBeanFactory = autowireCapableBeanFactory;
}

答案 2

您可以通过两个问题来解决此问题:

  • 尝试使用Spring在验证器上注入服务。

  • 手动初始化它,覆盖验证程序的初始化方法。

我前段时间遇到了同样的问题,最后我决定使用第二个选项来避免大量问题。

正如您所指出的,您必须在验证器上定义一个初始化方法,在那里您可以使用ServiceUtils来获取所需的服务bean:

@Autowired
private EmployeeService employeeService;

@Override
public void initialize(EmployeeValidation constraintAnnotation) {
  //Use an utility service to get Spring beans
  employeeService = ServiceUtils.getEmployeeService();
}

ServiceUtils是一个普通的Spring bean,在静态方法中使用对自身的静态引用。

@Component
public class ServiceUtils {
  private static ServiceUtils instance;

  @Autowired
  private EmployeeService employeeService;

  /* Post constructor */

  @PostConstruct
  public void fillInstance() {
    instance = this;
  }

  /*static methods */

  public static EmployeeService getEmployeeService) {
    return instance.employeeService;
  }
}

因此,您正在使用Spring来注入所需的服务,但不是以通常的方式。希望这有帮助。


推荐