1 概述
直接使用Spring提供的Validation机制来校验请求参数比较麻烦,还好hibernate-validator包提供了注解的方式,在参数对象的属性上加上对应的注解,即可进行校验,这样就方便多了。本文来了解一下hibernate-validator是如何把Spring的Validation机制扩展成用注解这种便利方式的。
2 原理
2.1 加载过程
1) 先依赖hibernate-validator包:
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<!-- 在spring-boot-dependencies里有管理配置 -->
<properties>
<hibernate-validator.version>6.2.5.Final</hibernate-validator.version>
</properties>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
2) 在hibernate-validator包里包含了文件/META-INF/services/javax.validation.spi.ValidationProvider,文件里配置了HibernateValidator类
org.hibernate.validator.HibernateValidator
Spring里提供了专门加载/META-INF/services目录的方法,正是通过这种方式可以支持第三方包来扩展。
3) 加载过程:
// 在spring-boot-autoconfigure包里有ValidationAutoConfiguration类,是一个带@AutoConfiguration注解的配置类。
// 当检测到classpath下有META-INF/services/javax.validation.spi.ValidationProvider时,
// 会触发ValidationAutoConfiguration这个配置类的加载。
// 源码位置:org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration
@AutoConfiguration
@ConditionalOnClass(ExecutableValidator.class)
@ConditionalOnResource(resources = "classpath:META-INF/services/javax.validation.spi.ValidationProvider")
@Import(PrimaryDefaultValidatorPostProcessor.class)
public class ValidationAutoConfiguration {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ConditionalOnMissingBean(Validator.class)
public static LocalValidatorFactoryBean defaultValidator(ApplicationContext applicationContext) {
// 1. 创建一个LocalValidatorFactoryBean对象,把对象作为bean
// LocalValidatorFactoryBean实现了InitializingBean接口,bean创建完成后执行afterPropertiesSet()
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory(applicationContext);
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
return factoryBean;
}
// 省略其它代码
}
// 源码位置:org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
public void afterPropertiesSet() {
Configuration<?> configuration;
if (this.providerClass != null) {
ProviderSpecificBootstrap bootstrap = Validation.byProvider(this.providerClass);
if (this.validationProviderResolver != null) {
bootstrap = bootstrap.providerResolver(this.validationProviderResolver);
}
configuration = bootstrap.configure();
}
else {
// 2. 加载默认的GenericBootstrap,其实现类为GenericBootstrapImpl
GenericBootstrap bootstrap = Validation.byDefaultProvider();
if (this.validationProviderResolver != null) {
bootstrap = bootstrap.providerResolver(this.validationProviderResolver);
}
// 3. 进行配置
configuration = bootstrap.configure();
}
if (this.applicationContext != null) {
try {
Method eclMethod = configuration.getClass().getMethod("externalClassLoader", ClassLoader.class);
ReflectionUtils.invokeMethod(eclMethod, configuration, this.applicationContext.getClassLoader());
}
catch (NoSuchMethodException ex) {
}
}
MessageInterpolator targetInterpolator = this.messageInterpolator;
if (targetInterpolator == null) {
targetInterpolator = configuration.getDefaultMessageInterpolator();
}
configuration.messageInterpolator(new LocaleContextMessageInterpolator(targetInterpolator));
if (this.traversableResolver != null) {
configuration.traversableResolver(this.traversableResolver);
}
ConstraintValidatorFactory targetConstraintValidatorFactory = this.constraintValidatorFactory;
if (targetConstraintValidatorFactory == null && this.applicationContext != null) {
targetConstraintValidatorFactory =
new SpringConstraintValidatorFactory(this.applicationContext.getAutowireCapableBeanFactory());
}
if (targetConstraintValidatorFactory != null) {
configuration.constraintValidatorFactory(targetConstraintValidatorFactory);
}
if (this.parameterNameDiscoverer != null) {
configureParameterNameProvider(this.parameterNameDiscoverer, configuration);
}
List<InputStream> mappingStreams = null;
if (this.mappingLocations != null) {
mappingStreams = new ArrayList<>(this.mappingLocations.length);
for (Resource location : this.mappingLocations) {
try {
InputStream stream = location.getInputStream();
mappingStreams.add(stream);
configuration.addMapping(stream);
}
catch (IOException ex) {
closeMappingStreams(mappingStreams);
throw new IllegalStateException("Cannot read mapping resource: " + location);
}
}
}
this.validationPropertyMap.forEach(configuration::addProperty);
if (this.configurationInitializer != null) {
this.configurationInitializer.accept(configuration);
}
postProcessConfiguration(configuration);
try {
this.validatorFactory = configuration.buildValidatorFactory();
setTargetValidator(this.validatorFactory.getValidator());
}
finally {
closeMappingStreams(mappingStreams);
}
}
// 源码位置:javax.validation.Validation.GenericBootstrapImpl
public Configuration<?> configure() {
// ValidationProviderResolver为DefaultValidationProviderResolver
ValidationProviderResolver resolver = this.resolver == null ? this.getDefaultValidationProviderResolver() : this.resolver;
List<ValidationProvider<?>> validationProviders;
try {
// 4. 加载所有ValidationProvider
validationProviders = resolver.getValidationProviders();
} catch (ValidationException e) {
throw e;
} catch (RuntimeException re) {
throw new ValidationException("Unable to get available provider resolvers.", re);
}
if (validationProviders.isEmpty()) {
String msg = "Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.";
throw new NoProviderFoundException(msg);
} else {
try {
Configuration<?> config = ((ValidationProvider)resolver.getValidationProviders().get(0)).createGenericConfiguration(this);
return config;
} catch (RuntimeException re) {
throw new ValidationException("Unable to instantiate Configuration.", re);
}
}
}
// 源码位置:javax.validation.Validation.DefaultValidationProviderResolver
public List<ValidationProvider<?>> getValidationProviders() {
// 5. 加载ValidationProvider列表
return Validation.GetValidationProviderListAction.getValidationProviderList();
}
// 源码位置:javax.validation.Validation.GetValidationProviderListAction
public static synchronized List<ValidationProvider<?>> getValidationProviderList() {
// 5. 执行run()方法加载,INSTANCE就是Validation.GetValidationProviderListAction的对象
return System.getSecurityManager() != null ? (List)AccessController.doPrivileged(INSTANCE) : INSTANCE.run();
}
// 源码位置:javax.validation.Validation.GetValidationProviderListAction
public List<ValidationProvider<?>> run() {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
List<ValidationProvider<?>> cachedContextClassLoaderProviderList = this.getCachedValidationProviders(classloader);
if (cachedContextClassLoaderProviderList != null) {
return cachedContextClassLoaderProviderList;
} else {
// 6. 使用ClassLoader去加载
List<ValidationProvider<?>> validationProviderList = this.loadProviders(classloader);
if (validationProviderList.isEmpty()) {
classloader = DefaultValidationProviderResolver.class.getClassLoader();
List<ValidationProvider<?>> cachedCurrentClassLoaderProviderList = this.getCachedValidationProviders(classloader);
if (cachedCurrentClassLoaderProviderList != null) {
return cachedCurrentClassLoaderProviderList;
}
validationProviderList = this.loadProviders(classloader);
}
// 加载到的类会缓存起来
this.cacheValidationProviders(classloader, validationProviderList);
return validationProviderList;
}
}
// 源码位置:javax.validation.Validation.GetValidationProviderListAction
private List<ValidationProvider<?>> loadProviders(ClassLoader classloader) {
// 7. ServiceLoader就是Spring提供的专门加载所有jar内META-INF/services/目录指定类型类的加载器,
// hibernate-validator包里有/META-INF/services/javax.validation.spi.ValidationProvider文件,
// 该文件里配置的org.hibernate.validator.HibernateValidator类就是ValidationProvider类型的
ServiceLoader<ValidationProvider> loader = ServiceLoader.load(ValidationProvider.class, classloader);
Iterator<ValidationProvider> providerIterator = loader.iterator();
List<ValidationProvider<?>> validationProviderList = new ArrayList();
while(providerIterator.hasNext()) {
try {
validationProviderList.add(providerIterator.next());
} catch (ServiceConfigurationError var6) {
}
}
// 这里列表里只有一个HibernateValidator对象
return validationProviderList;
}
// 回到GenericBootstrapImpl的configure()继续处理
// 源码位置:javax.validation.Validation.GenericBootstrapImpl
public Configuration<?> configure() {
// ValidationProviderResolver为DefaultValidationProviderResolver
ValidationProviderResolver resolver = this.resolver == null ? this.getDefaultValidationProviderResolver() : this.resolver;
List<ValidationProvider<?>> validationProviders;
try {
// 4. 加载所有ValidationProvider
validationProviders = resolver.getValidationProviders();
} catch (ValidationException e) {
throw e;
} catch (RuntimeException re) {
throw new ValidationException("Unable to get available provider resolvers.", re);
}
if (validationProviders.isEmpty()) {
String msg = "Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibe

最低0.47元/天 解锁文章
1425

被折叠的 条评论
为什么被折叠?



