JavaにはBean ValidationというAPIが存在していて、これはアノテーションによってバリデーションの制約を定義できるとても便利なものです。
Bean Validationの使い方
何かしらのクラスのメンバ変数に@NotNullとか、@Max(100)などというアノテーションを指定すると、nullでないことの検証や値の最大値の検証が簡単にできます。
public class Bean {
@NotNull
String attribute;
// ...
}
便利です。
Bean Validationの実装の比較
Bean Validationは、Javaの素晴らしき仕様と実装の分離の恩恵を受けていて、このBean Validationを実装したライブラリはひとつではないので、用途に応じて使い分けることができます。
Bean Validation API 1.0の実装の有名どころは、Hibernate ValidatorやApache BVal、GWT Validationなどです。
最近パフォーマンス検証をしていたら、どうもBean Validationがひどく負荷をかけているように感じたので、ひとつ比較をしてみようと思いました。
3つのライブラリの比較の方法
比較の方法を簡単に書いておきます。
Validatorを生成し、それを用いて1000回とか10,000回とかバリデーションをおこない実行時間を計測します。回数依存性を見るために、これを100回くらい立て続けに繰り返します。
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();
for (int j = 0; j < LOOP; j++) {
long start = System.nanoTime();
for (int i = 0; i < UNIT; i++) {
Bean bean = new Bean("attr");
validator.validate(bean);
}
System.out.println(((double) (System.nanoTime() - start) / 1e6));
}
3つのライブラリのMavenの依存定義は次のようにしました。
1つ目は、Hibernate Validatorです。最新の開発バージョンである、5.1.0.Alpha1です。(あとで別のバージョンも比較します)
org.hibernate
hibernate-validator
5.1.0.Alpha1
2つ目は、Apache BValです。
org.apache.bval
bval-jsr303
0.5
そして3つ目はGoogleのプロジェクト。GWT Validationです。
com.googlecode.gwt-validation
gwt-validation
2.1
比較結果
これは@NotNullをつけたクラスを10,000回ずつバリデーションした結果です。
比較すると、Hibernate Validatorが最も高速で、GWT Validationと比較すると桁が違います。どの実装も初回のバリデーションが一番遅く、何回かバリデーションを繰り返すと、処理時間が短くなるようです。くわしく実装は見ていないですが、バリデーションの定義をキャッシュする機構があるようです。
ところで、もともとこの調査をし始めたのは、Bean Validationのために使っているHibernate Validatorが遅いのではないかということを検証するためでした。しかし、実際に測定してみると、Hibernate Validatorは十分に高速でした。
Hibernate Validatorのバージョン比較
もう少し色々と測定して試してみると、Hibernate Validatorの5.0.0.Alpha1の@NotEmptyのバリデーションが遅いことが分かりました。
@NotNullと@NotEmptyをつけたクラスを、1,000回ずつバリデーションして処理時間を計測しています。
この通り、@NotEmptyのバリデーションは、Hibernate Validator 5.0.0.Alpha1では猛烈に遅くなります。回数を重ねるごとにどんどん遅くなっていくので、いずれハングアップすることになります。
@NotEmptyというのは、Bean Validationの仕様自体には存在しないもので、@NotNullと@Size(min=1)の複合的な定義となっています。Hibernate Validatorの5.0.0.Alpha2までは、このバリデーションがとてもヘビーなようです。
もう5.0.0.Alpha2はもう半年以上経過しているしそもそも安定バージョンじゃないので、そんなに使っている人はいないかもしれませんが、せっかく調べたのでメモ書き程度に。