クラスとテンプレートのライブリロード

Tapestry 5 のとても重要な新しい機能のひとつが、クラスとテンプレートの変更を自動的に再ロードするということです。

前のバージョンのTapestryは、開発モードのときだけテンプレートの再ロードをすることができました。 クラスの再ロードはサーブレットコンテナの再起動(またはWebアプリケーションの再デプロイ)が必要でした。

Tapestry 5 は、ページとコンポーネント のクラスが変更されると自動的に再ロードします。 コンポーネントテンプレートと他の関連するリソースが変更されたときも同様に、ただちに再ロードします。

テンプレートの再ロード

テンプレートが変更されると、ページインスタンス(及びページ内にあるコンポーネント階層)全てが破棄され、 新しいテンプレートで再構築されます。しかし、この場合はクラスの再ロードは行われません。

クラスの再ロード

Tapestryの管理下にあるパッケージ(及びそのサブパッケージ)内にあるロード済みのクラスの いずれかでも 変更があると、Tapestryはページインスタンス全てとクラスローダを破棄します。

通常、ページの永続フィールドのデータは(ページと切り離され、セッション内に格納されているので)影響を受けることはありません。 そのため、コンポーネントクラスへの大きな変更があってもアプリケーションの実行を継続することができます。

ページとコンポーネントのパッケージ

ページクラスとコンポーネントクラスだけが再ロードの対象です。

リロード対象かどうかはパッケージ名によって決まります; そのパッケージ名は アプリケーション設定 に基づいています。

ルートパッケージが org.example.myapp の場合、次のパッケージ内のクラスだけが自動再ロードの対象です:

  • org.example.myapp.pages
  • org.example.myapp.components
  • org.example.myapp.mixins
  • org.example.myapp.base

ファイルシステムのみ

クラスや他のファイルの再ロードは、ファイルシステム上に実際に存在しているファイルに対してのみ行われます。 JARファイル内から得られたファイルは再ロードの対象となりません。 開発時はファイルはローカルワークスペースにあるので、再ロードは適切に行われます。 本番環境にデプロイしたアプリケーションでは、サーブレットコンテナやアプリケーションサーバの実装次第です。

クラスローダの問題

Tapestryはページクラスとコンポーネントクラスをロードするために特別なクラスローダを用いています。

ページクラスやコンポーネントクラスのJavaクラスファイルが変更されたことを検出すると、Tapestryはそのクラスローダとプールされたページのインスタンスを破棄します。

Tapestryのページやコンポーネントへの参照を、Tapestry IoCサービスなど他のコード内で保持しないよう注意してください。 そのような参照の保持はクラスローダがガーベジコレクタによって回収されることを妨げるので、重大なメモリリークを引き起こします。

ClassCastException

サービスレイヤーを使用したり、あるいはコンポーネントではないオブジェクトにコンポーネントのインスタンスを渡したりすると、 Tapestryのクラスローダアーキテクチャがちょっとした頭痛の種になるかもしれません。

しばしば、ClassCastExceptionが発生するでしょう。 これは、複数の異なるクラスインスタンスが同じクラス名で、例えば org.example.myapp.pages.Start というクラス名で存在してしまうからです。 ひとつはWebアプリケーションのデフォルトクラスローダでロードされたクラスインスタンスで、 もうひとつは Tapestry の再ロード可能なクラスローダによってロードされ コード修正された クラスインスタンスです。

Tapestry IoCサービスのクラスのような普通のクラスはデフォルトクラスローダでロードされ、 インスタンスは同じクラスローダ(または親クラスローダ)によってロードされていることが期待されます。

解決方法はインターフェースを導入することです; コンポーネントクラスはインターフェースを実装し、 サービスに渡す際はコンポーネントの型としてではなくインターフェースの型で渡します。

そのインターフェースがデフォルトクラスローダでロードされることが重要なため、 ページやコンポーネントのパッケージではなくサービスのように他のパッケージに入れなければなりません。