【3】さまざまな参照をクリアしてメモリリーク防止
メモリリーク防止機能としてWebappClassLoader#clearReferences()が改良されました。WebappClassLoader#clearReferences()はWebAppクラスローダの停止時に呼び出され、クラスローダが保持する、さまざまな参照をクリアします。
以下にclearReferences()に新たに追加されたクリア処理をいくつか記載します。
■ JDBCドライバの参照をクリア
Webアプリケーションを停止するときに、ロードされているすべてのJDBCドライバから停止するWebアプリケーションのクラスローダによってロードされたJDBCドライバをderegisterDriverします。
これにより、JDBCドライバの参照残によるWebAppクラスローダのリークを防止します。このとき、以下のようなメッセージがエラーレベルで出力されます。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
■ 実行中スレッドの停止
Webアプリケーション停止時に、停止するWebアプリケーションのWebAppクラスローダがコンテキストクラスローダとなっている全ての実行中スレッドを停止します。
デフォルトでは、この機能をON/OFFする属性のclearReferencesStopThreadsやclearReferencesStopTimerThreadsがfalseに設定されているため、実際の停止までは行わず、以下のようなエラーメッセージのみを出力します(参考:Apache Tomcat 7 Configuration Reference (7.0.16) - The Context Container)。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
■ 削除されていないスレッドローカルのチェック
Webアプリケーション停止時に、起動中のスレッドに、停止するWebアプリケーションのWebAppクラスローダがロードしたThreadLocalが登録されているかどうかをチェックします。ThreadLocalが残っている場合は、以下のようなエラーログを出力します。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
実際のThreadLocalのリークによるWebAppクラスローダのリークを防止は、org.apache.catalina.core.ThreadLocalLeakPreventionListenerによって行われます。ThreadLocalLeakPreventionListenerはTomcat 7.0.6からデフォルトでserver.xmlに設定されています。
Tomcat 6の場合はThreadLocalLeakPreventionListenerがバックポートされていないので、Context#clearReferencesThreadLocalsでThreadLocalの削除を切り替えます(参考:Apache Tomcat Configuration Reference - The Context Container)。
【4】メモリリークの探知機能「Find leaks」
ManagerアプリケーションにFind leaksボタンが追加されました。Find leaksでは、Webアプリケーションが停止、リロード、アンデプロイしたときに本来破棄されていなければならないはずのWebAppクラスローダを検索し、もし残っていたらメモリリークと判断して、そのWebアプリケーションのパスを表示します。
なお、この機能では「System.gc()」メソッド(ガベージ・コレクション)を利用しているため、Javaのオプションなどで無効にしている場合は注意が必要です。
【5】さまざまなTomcatの実行方法が追加
Tomcatを利用するのに最も一般的な方法は、server.xmlを設定して、起動スクリプトから起動するというものです。Tomcat 7では、上記とは別の方法でTomcatを利用できます。それは、org.apache.catalina.startup.Tomcatクラスを利用する方法とJMXベースでのTomcatのコンフィグする方法です。
■ org.apache.catalina.startup.Tomcatクラス
Tomcat 7では、Tomcatをプログラムに組み込むためのAPIを提供します。その肝となるクラスが「o.a.c.startup.Tomcat」クラスです。o.a.c.startup.Tomcatクラスを利用することで数行程度のプログラムでアプリケーションにTomcatを組み込めます。以降では、Tomcatクラスを使ってカスタムTomcatを作成してみましょう。
public class TomcatEmbedded { public class TomcatEmbedded { public static void main(String[] args) { try { Tomcat tomcat = new Tomcat(); Context ctx = tomcat.addContext("/test", "/test"); Tomcat.addServlet(ctx, "hello", new HelloServlet()); ctx.addServletMapping("/helloworld", "hello"); tomcat.start(); tomcat.getServer().await(); } catch (LifecycleException e) { // TODO } } } // Servlet public class HelloServlet extends HttpServlet { private static final long serialVersionUID = 1L; @Override public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException { res.getWriter().write("Hello world"); } }
以下で、コードを細かく見ていきます。
Tomcat tomcat = new Tomcat();
基本となるo.a.c.startup.Tomcatのインスタンスを生成します。
Context ctx = tomcat.addContext("/test", "/test");
生成したTomcatインスタンスにContextを追加します。第1引数にコンテキストパス、第2引数にコンテキストのdocBaseを指定します。
Tomcat.addServlet(ctx, "hello", new HelloServlet());
生成したコンテキストにServletを追加します。第1引数にServletを追加するコンテキスト、第2引数に追加するServlet名、第3引数に追加するServletのインスタンスを指定します。
ctx.addServletMapping("/helloworld", "hello");
コンテキストにServletをマッピングします。第1引数にマッピングするパターン、第2引数にマッピングするServlet名を指定します。
tomcat.start();
準備ができたので、Tomcatを起動します。
tomcat.getServer().await();
メインスレッドが終了してしまうので、待ち合わせをします。「tomcat.getServer().await();」を呼び出すことでTomcatインスタンスを起動したメインスレッドがSHUTDOWN待ちの状態になります。
Webブラウザから「http://localhost:8080/test/helloworld」とリクエストすると”Hello world”と表示されます。数行程度のコードで簡単にTomcatを組み込めました。
■ JMX経由でTomcatを構成
Tomcat 7はJMX経由でTomcatを構成する機能を提供します。本機能を利用するには「ObjectName=Catalina:type=MBeanFactory」で定義されているMBeanを使用します。では、MBeanFactoryを使ってTomcatをコンフィグレーションしてみましょう。例えば、以下のような何も定義していないserver.xmlを容易します。
<?xml version='1.0' encoding='utf-8'?> <Server port="8005" shutdown="SHUTDOWN"> </Server>
このserver.xmlを指定してTomcatを起動したら準備は完了です。MBeanFactoryを利用してTomcatを作成していきます。今回はJConsoleを利用してみましょう。
MBeanFactoryには、Tomcatの構成要素を作成し、追加するようなメソッドが多く定義されています。これらのメソッド郡を利用することでTomcatを作成できます。
まず、createStandardServiceEngineを実行し、Engineを作成します。第3引数のbaseDirにはTomcatをインストールしたディレクトリを指定します。
次に、createStandardHostを実行し、作成したEngineにHostを登録します。第1引数の「parent」にはcreateStandardServiceEngineの返却値を指定します。第3引数の「appBase」にはアプリケーションを配置するディレクトリを指定します。
createHttpConnectorを実行し、HTTPリクエストを処理可能にします。後は、Host生成時に指定したappBaseにWebアプリケーションを配置すればTomcatがデプロイしてくれます。
簡単とは言えないですが、一応MBeanFactoryを利用してTomcatを構成できました。次ページでは、最後にちょっとした変更点を紹介して終わりにしたいと思います。
Copyright © ITmedia, Inc. All Rights Reserved.