GlassFishのホットデプロイ時間をみてみる(CDIバージョン)
前回はEJB(Stateless Session Bean)のホットデプロイ対象を見てみましたが、CDI(旧WebBeans)でsimple bean*1だとどうなるのかみてみました。
試したSimpleBeanは以下のような、メソッドが1つのコードです。
package org.example; import javax.inject.Named; @Named public class HelloService_1 { public void sayHello() { System.out.println("Hello!!"); } }
以下の表が結果です(EJBも合わせて書きました)
クラス数 | 時間(SLSB) | 時間(simple bean) |
---|---|---|
1 | 264ms | 293ms |
2 | 276ms | 318ms |
10 | 378ms | 356ms |
50 | 958ms | 455ms |
100 | 1,607ms | 593ms |
1000 | 18,208ms | 3,646ms |
simple beanも数に応じて時間が増えていきますが、EJBより圧倒的に軽い!?。インターセプタは今回利用していないので、使うとなると結果が変わってくるかもしれませんが。
もうちょっと利用機能を増やして次回は測ってみますかな。
追記
simple beanの@Namedを外して測定してみると、ほとんどデプロイ持間は変わりませんでした。もしかすると、CDI(Weldの実装)はデプロイ時の初期化処理はないのでしょうかねぇ...? 名前で引けるように、コンポーネントとして登録されているとは思うのですが。JBoss SeamだとComponentスキャンが行われていて、そこそこ時間がかかってたしなぁ。
さらに追記
@Injectでインジェクションしたsimple beanをgetClass()して標準出力に出してみたところ、エンハンスされていない素のクラスでした。これだと初期化処理は軽いかも。やっぱりsimple beanにインターセプタを組み込んで試してみた。
以下のログ出力インターセプタを示すアノテーションを作成。
package org.example; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.interceptor.InterceptorBinding; @InterceptorBinding @Inherited @Target( { ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) public @interface Logging { }
以下のログ出力インターセプタを作成。
package org.example; import javax.interceptor.AroundInvoke; import javax.interceptor.Interceptor; import javax.interceptor.InvocationContext; @Logging @Interceptor public class LoggingInterceptor { @AroundInvoke public Object logging(InvocationContext ctx) throws Exception { System.out.println("before called."); try { return ctx.proceed(); } finally { System.out.println("after called."); } } }
WEB-INF/beans.xmlに作成したインターセプタを登録。
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> <interceptors> <class>org.example.LoggingInterceptor</class> </interceptors> </beans>
そして、simple beanに作成したログ出力インターセプタのアノテーションを付与する。
package org.example; import javax.inject.Named; @Named @Logging public class HelloService { ... }
これでインターセプタが有効となります。beans.xmlの定義は無くても動いていいのにと思ったのですが、複数インターセプタを仕掛けるとなる順序制御が必要になってきたり、インターセプタを外したいといった場合のためにbeans.xmlに定義するようになっている模様です。
さすがにインターセプタがかかると@Injectしたクラスはエンハンスされており、以下のように出力されました。Seamと同じでjavassistでエンハンスされていますね。
情報: class org.example.HelloService_$$_javassist_78
では、これでクラス数を変えてまた測定してみます。
クラス数 | 時間(SLSB) | 時間(simple bean) | 時間(intercepted simple bean) |
---|---|---|---|
1 | 264ms | 293ms | 368ms |
2 | 276ms | 318ms | 377ms |
10 | 378ms | 356ms | 433ms |
50 | 958ms | 455ms | 544ms |
100 | 1,607ms | 593ms | 732ms |
1000 | 18,208ms | 3,646ms | 4,585ms*2 |
結果は上記の通り、インターセプタを組み込むコストのためデプロイ時間は増加してます。といっても、EJB(インターセプタなし)と比べるとかなり速い。
EJBのデプロイ時間が遅い理由は、ネーミングサービスの登録と言ったEJB固有の処理が多すぎるのでしょうか。また、EJBは過去の仕様もサポートしているため遅くなっている部分がありそう。まぁコンテナの実装次第ですが、EJB2のデプロイロジックを再利用してると遅そうな気はしますね。定義していないけど内部でローカルインタフェースを作ったりとかしてたりして。