Производительность 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

Выводы:

  1. Hibernate валидация на ровном месте даёт падение производительности в ~150 раз. Поэтому если Ваше приложение это low-latency система, то, возможно, стоит подумать сколько объектов нужно проверять и как много полей. Возможно (но не гарантированно) стоит делать проверки через static методы.
  2. Однако если посмотреть абсолютные величины, то заметно, что удобство и гибкость в настройки валидации стоит всего 0.002 миллисекунды. Если у Вас CRUD интернет приложение, то Hibernate validator будет гораздо лучшим выбором.