Производительность Hibernate Validator
Недавно столкнулся с библиотекой Hibernate Validator и jsr 303 в частности. Ниже привожу небольшой микро-бенчмарк тестирования производительности. Тестовый POJO:
public class BusinessObject {  
 	@NotBlank  
 	private String name;  
 	@CustomNotNull(groups = { APIValidationGroup.class })  
 	private String uuid;  
  
 	public String getName() {  
  		return name;  
 	}  
  
 	public void setName(String name) {  
  		this.name = name;  
 	}  
  
 	public String getUuid() {  
  		return uuid;  
 	}  
  
 	public void setUuid(String uuid) {  
  		this.uuid = uuid;  
 	}  
}  
Для чистоты эксперимента и приближения к реальному сценарию я сделал кастомную валидацию, которая просто проверяет на null:
public class CustomNotNullValidator implements ConstraintValidator<CustomNotNull, String> {  
 	public void initialize(CustomNotNull constraintAnnotation) {  
 	}  
   
 	public boolean isValid(String value, ConstraintValidatorContext context) {  
  		if( value == null ) {  
   			return false;  
  		}  
  		return true;  
 	}  
}
Собственно сам тест:
public static void main(String[] args) {  
 	int heatCount = 10000;  
	int count = 1000000;  
	Validator validator = Validation.buildDefaultValidatorFactory().getValidator();  
	BusinessObject validObject = new BusinessObject();  
	 validObject.setName("123");  
	 validObject.setUuid("123");  
	  
	 for (int i = 0; i < heatCount; i++) {  
	  validator.validate(validObject, Default.class);  
	 }  
	  
	 long start = System.currentTimeMillis();  
	 for (int i = 0; i < count; i++) {  
	  validator.validate(validObject, Default.class);  
	 }  
	 long diff = (System.currentTimeMillis() - start);  
	 System.out.println("hibernate validation absolute: " + diff + " avg: " + ((double)diff / count));  
	  
	 for (int i = 0; i < heatCount; i++) {  
	  validate(validObject);  
	 }  
	  
	 start = System.currentTimeMillis();  
	 for (int i = 0; i < count; i++) {  
	  validate(validObject);  
	 }  
	 diff = (System.currentTimeMillis() - start);  
	 System.out.println("static validation absolute: " + diff + " avg: " + ((double)diff / count));  
	  
	 start = System.currentTimeMillis();  
	 for (int i = 0; i < count; i++) {  
	  validator.validate(validObject, APIValidationGroup.class);  
	 }  
	 diff = (System.currentTimeMillis() - start);  
	 System.out.println("hibernate custom validation absolute: " + diff + " avg: " + ((double)diff / count));  
	  
	 start = System.currentTimeMillis();  
	 for (int i = 0; i < count; i++) {  
	  validateCustom(validObject);  
	 }  
	 diff = (System.currentTimeMillis() - start);  
	 System.out.println("static custom validation absolute: " + diff + " avg: " + ((double)diff / count));  
	}  
	  
	private static boolean validate(BusinessObject obj) {  
	 if (StringUtils.isBlank(obj.getName())) {  
	  return false;  
	 }  
	 return true;  
	}  
	  
	private static boolean validateCustom(BusinessObject obj) {  
	 if (!validate(obj)) {  
	  return false;  
	 }  
	 if (obj.getUuid() == null) {  
	  return false;  
	 }  
	 return true;  
}
Результаты выполнения следующие (hibernate validator 4.2.0.Final):
- hibernate validation absolute: 2410 avg: 0.00241
- static validation absolute: 17 avg: 1.7E-5
- hibernate custom validation absolute: 3407 avg: 0.003407
- static custom validation absolute: 16 avg: 1.6E-5
Выводы:
- Hibernate валидация на ровном месте даёт падение производительности в ~150 раз. Поэтому если Ваше приложение это low-latency система, то, возможно, стоит подумать сколько объектов нужно проверять и как много полей. Возможно (но не гарантированно) стоит делать проверки через static методы.
- Однако если посмотреть абсолютные величины, то заметно, что удобство и гибкость в настройки валидации стоит всего 0.002 миллисекунды. Если у Вас CRUD интернет приложение, то Hibernate validator будет гораздо лучшим выбором.
