我对Spring来说是全新的,我已经在SO上找到了一些问题的答案。以下是链接:
Spring 3.1 Autowiring does not work inside custom constraint validator
Autowiring a service into a validator
Autowired Repository is Null in Custom Constraint Validator
我有一个Spring项目,我想在其中使用Hibernate Validator进行对象验证。基于我在网上阅读的内容和一些论坛,我试图注入验证器如下:
@Bean
public Validator validator() {
return new LocalValidatorFactoryBean().getValidator();
}
但无论我在哪里使用
@Autowired
Validator validator;
它采用了Spring的验证器实现而不是Hibernate的验证器。我无法弄清楚如何准确地注入Hibernate验证器并简单地将其自动装配到其他类中,所以我使用了一个便宜的技巧,现在我的Java Config看起来像这样
@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;
}
}
在上面的Custom Constraint Validator中,我得到employeeService null。我知道Spring启动时没有实例化ConstraintValidator的任何实现,但我认为添加ValidatorImpl()实际上会解决这个问题。但事实并非如此。
现在我陷入了一个非常hacky的解决方法,我不想继续这样的代码。有人可以帮助我解决我的情况。
附:这些是我在Java Config文件中的导入:
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;
我希望解决方案可以帮助某人:
@Bean
public Validator validator () {
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure().constraintValidatorFactory(new SpringConstraintValidatorFactory(autowireCapableBeanFactory))
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
return validator;
}
使用SpringConstraintValidatorFactory
初始化验证器以便注入工作并将验证器实现提供为Hibernate.class以下列方式工作:
它是如何工作的:Hibernate的ConstraintValidatorFactory
没有初始化任何ConstraintValidators
,除非它们被调用但SpringConstraintValidatorFactory
通过给它AutowireCapableBeanFactory
。
编辑
正如@shabyasaschi的评论之一所述,要注入autowireCapableBeanFactory
,您可以将方法签名更改为:
Validator validator(final AutowireCapableBeanFactory autowireCapableBeanFactory) {
或者在配置文件中为它添加getter和setter,如下所示:
public AutowireCapableBeanFactory getAutowireCapableBeanFactory() {
return autowireCapableBeanFactory;
}
public void setAutowireCapableBeanFactory(AutowireCapableBeanFactory autowireCapableBeanFactory) {
this.autowireCapableBeanFactory = autowireCapableBeanFactory;
}
在你的bean定义中
@Bean
public Validator validator() {
return new LocalValidatorFactoryBean().getValidator();
}
方法定义中Validator
的类型是什么?你应该确保它从Spring返回javax.validation.Validator
,而不是Validator
。
让Spring引导验证器也会导致将SpringConstraintValidatorFactory
传递给Hibernate Validator,这将在约束验证器中启用依赖注入。
您可以通过两种方法解决此问题:
我很久以前遇到了同样的问题,最后我决定使用第二种选择避免大量问题。
正如您所指出的,您必须在验证器上定义一个初始化方法,并且您可以使用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注入所需的服务,但不是通常的方式。希望这可以帮助。
那对我有用。对于那些现在搜索的人
public class EmployeeValidator implements ConstraintValidator<EmployeeValidation , Object> {
private EmployeeService employeeService;
public EmployeeValidator(EmployeeService employeeService){
this.employeeService = employeeService;
}
...
}
private XXXService xxxService = SpringContextHolder.getBean(XXXService.class);