J2EEレガシーアプリケーションのJavaEEアプリケーションへのマイグレーション(2)
何回かに分けてJ2EEレガシーアプリケーションのJavaEEアプリケーションへのマイグレーションについて実際のコードを見ながら解説したいと思います。
変更前のサンプルソースはこちら
https://github.com/megascus/oi-webapp-sample/tree/initial
第一回はこちら
J2EEレガシーアプリケーションのJavaEEアプリケーションへのマイグレーション(1)
今回はHibiernateをJPA(Eclipse Link)に置き換えたいと思います。
hibernate.cfg.xmlからpersistance.xmlへの置き換え
hibernate.cfg.xmlは削除してしまいます。その代わりにpersistance.xmlを置きます。
https://github.com/megascus/oi-webapp-sample/blob/initial/src/hibernate.cfg.xml
https://github.com/megascus/oi-webapp-sample/blob/20140430/conf/persistence.xml*1
また、hibernate固有の設定は削除し、Connection poolをHibernateのものを使用していたのをGlassfish(APサーバー)から取得するようにDataSourceの設定を行いました。
商用APサーバーには高機能なConnection poolが用意されている場合もありますので、明確な理由がない場合以外はAPサーバーのConnection poolを使用することをお勧めいたします。
Hibernate SessionのEntity Managerへの置き換え
JPAはHibernateを基に仕様策定されているため、基本的なクラス群はメソッド名の変更程度で単純に置き換えることができるようになっています。
今回のアプリケーションでもほぼそのまま置き換えることができるのですが、せっかくなので以下のような修正を追加でくわえたいと思います。
- EntityManagerはAPサーバー(コンテナ)管理とする。コンテナ管理とすることでトランザクションがスレッドに紐づけられ、アプリケーションでの明示的なトランザクション管理(commit、rollback)をする必要がなくなる。
コンテナの管理とすることで、クラスのインスタンスの直接的な作成をしてはいけなくなる等制限もでてきますが、それに見合った利益を享受することができます。
note.
もともとのアプリケーションではHTTPリクエストごとにServiceRegistry、SessionFactoryが生成されていましたが、実運用では絶対にやらないでください。
リクエストごとにHibernateの初期化が行われるため性能面で著しい問題が発生します。
たとえJPAに置き換えない場合でもこちらだけは絶対に修正する必要があります。
https://github.com/megascus/oi-webapp-sample/blob/initial/src/com/oisix/sample/bean/CustomerSearchBean.java#L43-L46
persistence.xmlを置いたことでEntityManagerは既に使用できる準備は整っています。
素のEntityManagerだと使いにくいため、以下のようなAbstractなラッパークラスを用意します。
https://github.com/megascus/oi-webapp-sample/blob/20140430/src/com/oisix/sample/dao/AbstractRepository.java
実装クラスは以下の通りです。
https://github.com/megascus/oi-webapp-sample/blob/20140430/src/com/oisix/sample/dao/MstCustomerRepository.java
もともとの実装ではDaoクラスで実装されていたものをAbstractRepositoryに移植しました。*2
https://github.com/megascus/oi-webapp-sample/blob/initial/src/com/oisix/sample/dao/MstCustomerDao.java
AbstractRepository自体はNetBeansで似たようなものが生成される程度のベストプラクティスです。
明らかに反対する理由がない限りは作成することを推奨します。
また、EJBをコンテナ管理とするために、EJB(Stateless Session Bean)としていることに注意してください。@Statelessアノテーションをつけています。
トランザクション管理のコンテナ管理化と業務処理のEJB化
業務処理はCustomerXXXBeanに記載されています。
https://github.com/megascus/oi-webapp-sample/blob/initial/src/com/oisix/sample/bean/CustomerEditBean.java
こちらをコンテナ管理とします。
https://github.com/megascus/oi-webapp-sample/blob/20140430/src/com/oisix/sample/bean/CustomerEditBean.java
コンテナ管理とするために、@Statefulアノテーションをつけて、EJBとしています。
また、コンテナ管理されたクラスには別のコンテナ管理されたクラスをDIすることができますので、MstCustomerRepository をDIしています。
また、トランザクション管理をコンテナ任せにすることで実際の処理の記述量が削減されていることを確認してください。
https://github.com/megascus/oi-webapp-sample/blob/initial/src/com/oisix/sample/bean/CustomerEditBean.java#L62-L84
↓
https://github.com/megascus/oi-webapp-sample/blob/20140430/src/com/oisix/sample/bean/CustomerEditBean.java#L59-L61
他の業務ロジックのクラスにも同様の修正を加えます。
note.
EJBには状態を保持するStateful Session Beanと状態を保持しないStateless Session Beanとアプリケーション内でユニークになるSingleton Session Beanの3種類が存在します。
今回は解説しませんが、きちんと使い分けないと予期しない不具合が発生する場合がありますのでご注意ください。
基本的にはEJBにはDIするためのフィールド以外は持たせず、Stateless Session Beanとするのが良いと思います。
コンテナ管理外からのEJB呼び出し
コンテナ管理されたクラスには別のコンテナ管理されたクラスをDIすることができるので簡単に呼び出せます。
しかしながら、コンテナ管理外からは呼び出すのに一工夫が必要となります。
以下のようなクラスを作成します。
https://github.com/megascus/oi-webapp-sample/blob/20140430/src/com/oisix/sample/util/EJBFactory.java
使う場合は以下のようにします。
https://github.com/megascus/oi-webapp-sample/blob/20140430/src/com/oisix/sample/base/ControllerServlet.java#L46-L47
まとめ
以上でHibernateのJPAへの置き換えが完了しました。
次回はServlet、JSP等のView側の修正を行っていきたいと思います。
また、以下のタグはここまでを修正したものになっています。
動く状態にはなっていますので、参考にしてください。
https://github.com/megascus/oi-webapp-sample/tree/20140430