本文へジャンプ

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。プロフィールで選択した情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

  • 閉じる [x]

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


送信されたすべての情報は安全です。

  • 閉じる [x]

Grails をマスターする: エンタープライズでの Grails

JMX、Spring、log4j で Grails を使用する方法

Scott Davis, Editor in Chief, AboutGroovy.com
Scott Davis
Scott Davis は国際的に知られた著者、講演者、そしてソフトウェア開発者です。彼の著書には、『Groovy Recipes: Greasing the Wheels of Java』、『GIS for Web Developers: Adding Where to Your Application』、『The Google Maps API』、『JBoss At Work』などがあります。

概要: 連載「Grails をマスターする」の今回の記事では、著者 Scott Davis が、Grails は果たしてエンタープライズに対応する準備ができているかどうかという不安を解消します。JMX (Java™ Management Extensions)、Spring、log4j をはじめとするエンタープライズ・レベルのライブラリーで Grails を使う方法を学んでください。

このシリーズの他の記事を見る

日付:  2008年 12月 16日
レベル:  初級 この記事の原文:  英語
アクティビティー: 6032 ビュー
お気軽にご意見・ご感想をお寄せください: 


Grails はエンタープライズに対応すると思うかという質問を受けることがよくあります。手短には「そう思う」と答えますが、詳しく説明する場合にはこう付け加えます。「ただしそれは、Spring や Hibernate (Grails のベースとなる基礎技術)、Tomcat や JBoss (使用している Java EE (Java Enterprise Edition) アプリケーション・サーバー)、MySQL や PostgreSQL (使用しているデータベース)、そしてJava プログラミングがエンタープライズに対応している、とユーザーが考えている場合に限ります」。

近頃 British Sky Broadcasting Group では、一般公開用の Web サイトを Grails に移行しました。このサイトには現在、毎月 1億1千万件のアクセスがあります。LinkedIn.com ではサイトのコマーシャルの一部に Grails を使用しています。Tropicana Juice の英国での Web サイトは、もう何年もの間、Grails で実行されています。Grails.org 自体も Grails で作成されていて、毎月 70,000 件を超えるダウンロードをサポートしています。また、最近の SpringSource による G2One (Groovy および Grails の後ろ盾となっている企業) の買収は、Groovy と Grails がエンタープライズに対応するかどうかという根強い不安感を和らげることになるはずです。

Groovy は時には突飛に見えることもあるだけに、これが昔ながらの通常の Java コードで実装されていることは忘れてはならない肝心な点です。Grails 開発は他の標準的な Java Web フレームワークとはまったく異なりますが、最終的には今までの開発と同じく、Java EE準拠の WAR ファイルとなります。

今回の記事では、エンタープライズ級の監視および構成用ツールについて探ります。まずは Grails アプリケーションを JMX によってインスツルメント化する方法を説明し、Grails での Spring 構成についても簡単に紹介します。さらに、log4j の初期設定を Config.groovy に指定する方法、そしてこの設定を JMX で動的に調整する方法も説明します。

この連載について

Grails は、Spring や Hibernate などのよく知られた Java 技術に「Convention over Configuration (設定より規約)」といった現代のプラクティスを盛り込んだ最新の Web 開発フレームワークです。Groovy で作成された Grails は既存の Java コードをシームレスに統合するだけでなく、スクリプト言語ならではの柔軟性と動的機能を与えてくれます。Grails を学んだら、Web 開発に対する今までの見方がまったく違ってくるはずです。

JMX によるインスツルメント化

2000年から出回っている JMX は、最も歴史のある JSR (正確には JSR 3) の 1 つです。Java 言語は、サーバーでの言語として一般に受け入れられたことから、実行中のアプリケーションをリモートから調整および構成できることが、プラットフォームに不可欠な部分となってきました。そこで、Sun では 2004年、JMX と付属のサポート・ツール (Java 1.5 JDK の JConsoleなど) によって JVM のインスツルメント化を行いました。

JMX は、JVM、アプリケーション・サーバー、使用するクラスのイントロスペクションをすべて、一貫したインターフェースで行います。インストロスペクションの対象となるさまざまなコンポーネントは、管理 Bean (略して Mbean) を介して管理コンソールに表示されます。

JMX の詳しい背景事情については、「Java の理論と実践: JMX を使ったアプリのインスツルメンテーション」を参照してください。

MBean はいわば、車のダッシュボードに搭載されたさまざまな計器、目盛盤、スイッチのようなものです。インスツルメントは、例えばスピードメーターのように読み取り専用であることもあれば、アクセルのように書き込み可能であることもあります。けれどもこのダッシュボードの例えは、MBean がリモートから管理されるように意図されている点を考えると多少合わなくなってきます。車のウィンカーを出したり、ラジオ局を変えたりするといった操作は、リモートからは行わないからです。

ローカル JMX エージェントを有効にする

ローカルとリモートとの違い

開発とテストの段階では、一般に、JMX エージェントとクライアントの両方をローカルで実行するのが最も手軽な方法です。一方、実際の本番環境ではリモートからエージェントの監視を行いますが、この際に JMX の利点が明らかになります。JConsole は 他のあらゆる Java プロセスと同じシステム・リソース (RAM、CPU サイクルなど) を使用します。このことは (監視対象の本番サーバーがすでに負荷状態にある場合は特に) 問題になる可能性がありますが、それよりも、JConsole を使うことで複数のサーバーを 1 箇所で監視することが可能になり、デジタル・ドメイン全体を把握できるようになることの方が重要です。

本番サーバーをリモートから監視するということは、当然、適切なセキュリティー対策も講じなければならないことを意味します。そのための方法としてはパスワードの保護を使用するか、あるいは理想的な方法としては公開/秘密鍵認証 (「参考文献」を参照) を使用します。

JMX を使用して監視するには、まず JMX を有効にしなければなりません。Java 5では、JVM の実行時に JMX 関連のフラグをいくつか指定する必要があります (Java 6では、デフォルトでこれらの設定がされていますが、フラグを指定して設定されている内容を変更することもできます)。このセットアップのことを JMX では、JMX エージェントのセットアップと言います。リスト 1 に、JVM パラメーターを記載します。


リスト 1. JMX による監視を有効にするJVM パラメーター

-Dcom.sun.management.jmxremote 
-Djava.rmi.server.hostname=localhost

チュートリアルのなかには、JMX フラグを保持するためのグローバル JAVA_OPTS 環境変数を作成するように推奨しているものもあれば、コマンドラインにフラグ、java -Dcom.sun.management.jmxremote -Djava.rmi.server.hostname=localhost someExampleClass を入力するように指示しているものもあります。

どちらの方法も上手くいくものの、本番環境に最適であるとは言えません。そこで私が見つけた最善の方法は、これらの値をサーバーの起動スクリプトに設定することです。毎回サーバーを再起動するたびに、上記のような難解なフラグを忘れずに入力しなければならないのでは、確実なソリューションにはなりません。また、CLASSPATHJAVA_OPTS のようなグローバル変数を設定することは、2 つの理由から避けるべきです。その 1 つは、サーバーを複製する際に不要な構成ステップが増えること (起動スクリプトが一貫していれば、サーバー間のコピーが遙かに簡単になります)、そしてもう 1 つは、同じマシン上のすべての Java プロセスが同じ構成を共有せざるを得なくなることです。もちろん、これらの面倒な構成の詳細を思い出せるように詳細なチェックリストを作成するという方法も可能ですが、複雑な内容を文書化することは、複雑さを取り除くよりもはるかに非効率的な結果になります。

UNIX®、Linux®、および Mac OS X システムでの Grails 起動スクリプトは $GRAILS_HOME/bin/grails です。このファイルを編集して、リスト 2 に記載する 2 つの JAVA_OPTS 行を追加してください。


リスト 2. Grails 起動スクリプトでの JMX による監視の有効化 (UNIX、Linux、および Mac OS Xの場合)

#!/bin/sh
DIRNAME='dirname "$0"'
. "$DIRNAME/startGrails"

export JAVA_OPTS="-Dcom.sun.management.jmxremote"
export JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=localhost"

startGrails org.codehaus.groovy.grails.cli.GrailsScriptRunner "$@"

Windows® での Grails 起動スクリプトは $GRAILS_HOME/bin/grails.bat です。この grails.bat ファイルにリスト 3 に記載する 2 行を追加してから、startGrails.bat を呼び出します。


リスト 3. Grails 起動スクリプトでの JMX による監視の有効化 (Windows の場合)

set JAVA_OPTS=-Dcom.sun.management.jmxremote
set JAVA_OPTS=%JAVA_OPTS% -Djava.rmi.server.hostname=localhost

両方のスクリプトで注目すべき点は、最初の JAVA_OPTS 変数の設定で、グローバル環境変数 (存在する場合) を無効にしていることです (グローバル環境変数の設定は、この単一のプロセスでのみ無効にされます。システム全体でグローバル変数が再度設定されることはありません)。このようにしているのは、グローバル設定によってローカル設定に悪影響が及ぼされないようにするためです。既に設定されているグローバル環境変数に依存している場合には、必ず、その既存の変数を設定の先頭で行うようにしてください。リスト 2 と 3 の 2 番目の JAVA_OPTS 変数の設定でも、そのようにしています。

早速、grails run-app と入力して Grails を起動してください。コンソールの出力には何の違いも現れませんが、アプリケーション・サーバーは監視できる状態になっています。

JMX エージェントを監視するには、JMX クライアントを使用します。このクライアントは、JConsole (Java 5 以降に付属) のようなデスクトップ GUI でも、Web UI (Tomcat や JBoss などのサーバーのほとんどに付属) でも構いません。さらに、エージェントをプログラムで監視することもできます。その方法については、この記事の終わりのほうで説明します。

別のコマンド・ウィンドウを開き、jconsole と入力します。ローカル JMX エージェントのリストには、Grails が表示されるはずです (図 1 を参照)。Grails をクリックしてから、Connect ボタンをクリックしてください。


図 1. JConsole にリストアップされたローカルの JMX エージェント

セキュリティー上の理由から、ローカルでの JMX エージェントへのアクセスは NTFS を使用する Windows システムでしか行うことができません。そのため、お使いのシステムが FAT または FAT32 を使用している場合には、問題が発生する可能性がありますが、心配は無用です。次のセクションで、リモート・アクセスが可能な JMX エージェントをセットアップする方法を説明します。厳密にはエージェントとクライアントの両方が同じマシン上にあるとしても、このセットアップ方法によってローカル・セキュリティーの問題を回避することができます。

接続が完了すると、図 2 のような要約ページが表示されます。


図 2. JConsole の要約ページ

ここで、Memory タブ、Threads タブ、Classes タブ、VM タブをひと通りクリックしてみてください。これらのタブには、JVM 内部での動作がリアルタイムで表示されます。この表示から、サーバーの物理メモリーが不足しているかどうか、ライブ・スレッドの数がどれだけあるか、さらにはサーバーが起動してからどれくらいの時間が経っているかがわかります。どのタブも興味深いものですが、この後注目するタブは、クラスが表示される MBeans タブです。

リモート JMX エージェントを有効にする

実稼働環境では使わないでください

この構成は実稼働環境では決して使用しないでください。説明のために、すべての認証と暗号化は無効に設定してあるからです。リモート管理用の JMX エージェントをセキュアにする詳細の手順については、「参考文献」を参照してください。

リモート接続を受け入れるように JMX エージェントをセットアップするには、いくつかの JMX 関連のフラグを JVM に渡す必要があります。これらの追加フラグが管理ポートを開き、セキュリティー設定 (この例では、セキュリティーが設定されていません) を構成します。

Grails 起動スクリプトに、リスト 4 に記載する新たな 3 行を追加します。


リスト 4. Grails 起動スクリプトでのリモート JMX による監視の有効化

export JAVA_OPTS="-Dcom.sun.management.jmxremote"    
export JAVA_OPTS=" $JAVA_OPTS -Djava.rmi.server.hostname=localhost"
export JAVA_OPTS=" $JAVA_OPTS -Dcom.sun.management.jmxremote.port=9004"
export JAVA_OPTS=" $JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
export JAVA_OPTS=" $JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false"

Grails を再起動して新しい設定を有効にします。JConsole も同じく再起動してください。今度は Remote タブをクリックして、localhost のポート 9004 に接続します (図 3 を参照)


図 3. JConsole でのリモート JMX エージェントへの接続

リモート JVM (理論的には同じシステム上で実行されていますが) にアクセスしていることを確認する簡単な方法としては、まず、MBeans タブをクリックします。左側の java.lang ツリーを展開し、Runtime 要素をクリックします。次に、画面右側の Attributes ウィンドウに表示されている InputArguments をダブルクリックします。すると、リモート JMX の設定すべてが表示されるはずです (図 4 を参照)。


図 4. JVM に渡された JMX リモート・エージェント・フラグ

上記のウィンドウを開いたまま、Connection メニューをクリックして新しい接続を開いてください。Remote タブをクリックして、今回はデフォルトを受け入れます (localhost のポート 0)。そして Runtime MBean の InputArguments を展開すると、そこにはリモート JMX フラグが表示されていないことに注目してください (図 5 を参照)。


図 5. 2 つの異なる JMX エージェントの監視

タイトル・バー (Monitoring Self) が十分なヒントにならない場合は、2 番目に開いた JConsole ウィンドウを見てください。このウィンドウから、JConsole アプリケーション自体を監視していることがわかります。

JConsole が立ち上がって Grails アプリケーションを監視するようになったところで、今度はロギング設定を調整するなどの実用的な操作を行いますが、その前に、JMX のパズルを完成させる最後の 1 ピース、MBean サーバーについて理解しておく必要があります。


MBean サーバー、Grails、そして Spring

JConsole でクリックした Runtime 要素は、MBean です。MBean が JMX クライアントに公開されるようにするには、JMX エージェントの内部で稼働する MBean サーバーに登録する必要があります。「JMX エージェント」と「MBean サーバー」という言葉を同じ意味で使う人もいますが、厳密に言えば MBean サーバーは JMX エージェント内部で稼働する多くのコンポーネントの 1 つです。

MBean をプログラムで登録するためには、MBeanServer.registerMBean() を呼び出します。ただし Grails では、MBean を管理するのは構成ファイル、正確には Spring 構成ファイルです。

Spring は Grails の心臓部です。Spring は、すべてのクラスについて、クラスが相互に作用する方法を制御する依存性注入フレームワークです (Spring についての詳細は、「参考文献」を参照してください)。

JMX の観点から言うと「MBean を MBean サーバーに登録している」と考えることができますが、Spring の観点からは、「MBean を MBean サーバーに注入している」と考える必要があります。使っている動詞は違うものの、最終的な結果は同じです。つまり、MBean が JMX クライアントに見えるようになります。

まず始めに、resources.xml という名前のファイルを grails-app/conf/spring 内に作成してください (resources.groovy と resources.xml との関係は、後で説明します)。リスト 5 に、resources.xml の一部を抜粋します。


リスト 5. resources.xml での Spring/JMX インフラストラクチャーのセットアップ

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

  <bean id="mbeanServer" 
        class="org.springframework.jmx.support.MBeanServerFactoryBean">
   	<property name="locateExistingServerIfPossible" value="true" />
  </bean>
  
  <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">	
    <property name="server" ref="mbeanServer"/>
    <property name="beans">
      <map>
      </map>
    </property>
  </bean>   
</beans>

基本構成が正しいことを確実にするために、この時点で Grails をリブートすることもできますが、パズルはまだ半分しか完成していません。MBean サーバーは用意できましたが、MBean がまだ用意されていないからです。MBean を登録するために必要なインフラストラクチャーとしては、上記に示されている mbeanServer と exporter という 2 つの Bean があります。mbeanServer Bean は、既存の MBean サーバーへの参照を保持します。そしてこの mbeanServer Bean が注入される exporter Bean は、MBean のリストを JConsole などの JMX クライアントに公開するクラスです。残るは、exporter Bean 内部の Bean のマップに MBean を追加して、MBean を登録すればよいだけとなりました。この作業は、次のセクションで行います。


Grails での log4j の使用

grails-app/conf/Config.groovy を開いて、log4j の設定を確認してください (リスト 6 を参照)。


リスト 6. Config.groovy での log4j の設定

log4j {
    appender.stdout = "org.apache.log4j.ConsoleAppender"
    appender.'stdout.layout'="org.apache.log4j.PatternLayout"
    appender.'stdout.layout.ConversionPattern'='[%r] %c{2} %m%n'
    // and so on...
}

Grails アプリケーションを開始するときに、コマンド・プロンプトに次々に表示されるメッセージのほとんどは log4j メッセージです。これは、org.apache.log4j.ConsoleAppender のおかげです (log4j の基本についての詳細は、「参考文献」を参照)。

log4j MBean を登録する

Grails アプリケーションのロギング設定を JMX なしで調整するには、上記のファイルを編集してサーバーをリブートします。一方、サーバーをリブートせずにロギング設定を調整したい場合、あるいはリモートからロギング設定を調整したい場合にはどうすればよいのでしょうか。このような調整が可能であれば、JMX には完璧な方法に思えます。幸い、log4j にはこれらのタスクを容易にするための MBean が付属しています。必要となる作業は、log4j MBean を登録することだけです。

entry 用の XML (リスト 7 を参照) を resources.xml に追加してください。これによって log4j MBean が MBean サーバーに注入されます。


リスト 7. MBean サーバーへの MBean の注入

<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">	
  <property name="server" ref="mbeanServer"/>
  <property name="beans">
    <map>
      <entry key="log4j:hierarchy=default">
        <bean class="org.apache.log4j.jmx.HierarchyDynamicMBean"/>
      </entry>        
    </map>
  </property>
</bean>

Grails をリブートしてから、JConsole を再起動します。localhost のポート 9004 に接続すると、MBeans タブには新たに log4j MBean が表示されているはずです。log4j ツリー要素を展開し、デフォルトをクリックしてから Info タブをクリックします。たった今 resources.xml に追加したエントリーの構成スニペットを確認できるはずです (図 6 を参照)。


図 6. デフォルト MBean 情報の表示

JMX を介して log4j を確認できるようになったので、次のステップでは、ロギング設定の一部を調整します。

log4j の設定をオンザフライで変更する

仮定として、Grails アプリケーションの動作が正常ではないとします。そういう場合には、内部で何が起こっているのかをよく把握しなければなりません。そこで、grails-app/conf/Config.groovy を調べたところ、ルート・ロガーは出力をコンソールに送信している一方、フィルターは error に設定されていることがわかりました (rootLogger="error,stdout")。コンソール出力の量を増やすためには、ログ・レベルを trace に設定しなおす必要があります。

JConsole を見てください。log4j フォルダーの下に、root MBean があります。その priority 属性は、Config.groovy での設定と同じく、ERROR に設定されているので、ERROR の値をダブルクリックして TRACE と入力します (図 7 を参照)。


図 7. ERROR から TRACE に変更されたルート・ロガーの priority 属性

コンソールに前よりもたくさんの情報が表示されるようになったことを確認するには、ブラウザーで Grails アプリケーションのホーム・ページにアクセスし、AirportMappingController へのリンクをクリックします。膨大な量の新しい出力のなかに、Grails が初期リストを表示するために実際に行っている内容についての詳細が見つかるはずです。リスト 8 はその一例です。


リスト 8. 増加した log4j 出力

[11277653] metaclass.RedirectDynamicMethod 
  Dynamic method [redirect] looking up URL mapping for 
  controller [airportMapping] and action [list] and 
  params [["action":"index", "controller":"airportMapping"]] 
  with [URL Mappings
------------
org.codehaus.groovy.grails.web.mapping.ResponseCodeUrlMapping@1bab0b
/rest/airport/(*)?
/(*)/(*)?/(*)?
]
[11277653] metaclass.RedirectDynamicMethod Dynamic method 
  [redirect] mapped to URL [/trip/airportMapping/list]
[11277653] metaclass.RedirectDynamicMethod Dynamic method 
  [redirect] forwarding request to [/trip/airportMapping/list]
[11277653] metaclass.RedirectDynamicMethod Executing redirect 
  with response 
  [com.opensymphony.module.sitemesh.filter.PageResponseWrapper@19243f]

Fatal Error を無視しても構わない場合

Grails 1.0.3 を暫く実行していると、コンソール出力に [Fatal Error] :-1:-1: Premature end of file という不可解なエラーが度々表示されることに気付くはずです。致命的なエラーやその他のエラーを引き起こすことにはなりそうにもないため、ほとんどの人はこれを無視しています。

ログ・レベルを trace に引き上げると、致命的であると思われるエラーに関する詳細、converters.XMLParsingParameterCreationListener Error parsing incoming XML request: Error parsing XML を確認することができます。

この詳細なログ出力に説明されているように、Grails は着信するすべてのリクエストを XML であるかのように構文解析しようとします。ほとんどのリクエストは XML ではないため、リクエスト・ハンドラーは然るべくエラーをレポートしますが、結局は正しくリクエストを処理します。

この「オオカミ少年的な些細なバグ」は、バージョン 1.0.4 では修正されています。

log4j の ConversionPattern を変更する

ここで、出力に使用するパターンを変更します。Config.groovyでパターンを設定するために使用されている行は、appender.'stdout.layout.ConversionPattern'='[%r] %c{2} %m%n' です。log4j のドキュメントを参考に、これをより説明的なパターンに設定することにしました。

JConsole で stdout MBean をクリックします。conversionPattern 属性の元の値を [%5p] %d{hh:mm:ss} (%F:%M:%L)%n%m%n%n に変更します。この魔法の呪文にどのような効果があるのかは、新しいログ出力を生成してから説明することにします (conversionPattern の設定についての詳細は、「参考文献」を参照してください)。


図 8. PatternLayout での conversionPattern の変更

Web ブラウザーでホーム・リンクをクリックし、もう一度 AirportMappingController リンクをクリックします。出力のフォーマットは大々的に変わっています (リスト 9 を参照)。


リスト 9. 新しい conversionPattern を使用したコンソール出力

[DEBUG] 09:04:47 (RedirectDynamicMethod.java:invoke:127)
Dynamic method [redirect] looking up URL mapping for controller 
[airportMapping] and action [list] and params 
[["action":"index", "controller":"airportMapping"]] with [URL Mappings
------------
org.codehaus.groovy.grails.web.mapping.ResponseCodeUrlMapping@e73cb7
/rest/airport/(*)?
/(*)/(*)?/(*)?
]

[DEBUG] 09:04:47 (RedirectDynamicMethod.java:invoke:144)
Dynamic method [redirect] mapped to URL [/trip/airportMapping/list]

[DEBUG] 09:04:47 (RedirectDynamicMethod.java:redirectResponse:162)
Dynamic method [redirect] forwarding request to [/trip/airportMapping/list]

[DEBUG] 09:04:47 (RedirectDynamicMethod.java:redirectResponse:168)
Executing redirect with response 
   [com.opensymphony.module.sitemesh.filter.PageResponseWrapper@47b2e7]

出力を確認できたところで、何が行われているのかを説明しましょう。まず、%p は priority 属性のレベルを書き出します。これらのメッセージは明らかに DEBUG レベルです。%d{hh:mm:ss} が、「時:分:秒」の形で日付スタンプを示し、(%F:%M:%L) が括弧内にファイル名、メソッド、そして行番号を示します。そして最後に %n%m%n%n が、新しい行、メッセージ、追加の 2 行を書き込むというわけです。

JMX を介して log4j に行った変更はいずれも永続化されません。そのため Grails をリブートすると、Config.groovy での永続設定に戻ります。つまり、設定を永久に台無しにしてしまうことは心配せずに、思いのままに JMX 設定を試してみることができます。ConversionPattern の場合、最適な設定を見つけるまで試行錯誤を繰り返して最適な設定を見つけるには、JMX を使用するのがうってつけの方法です。ただし、変更を永続化させるにはパターンを Config.groovy にコピーすることを忘れないでください。


Hibernate DEBUG 出力の確認

実行中の Grails アプリケーションをデバッグするという仮定の話に戻ると、動作が正常でない原因はまだ見つかっていません。そこで、root MBean の priority 属性を ERROR の設定に戻し、不要な情報を削減することにします。

問題は、Hibernate にある可能性があります。Config.groovy をもう一度見てみると、org.hibernate パッケージのロギング出力は off に設定されています。アプリケーション全体に対する出力レベルを上げるよりも、特定のパッケージに焦点を絞ったほうが、より多くの情報を得られることになります。

JConsole で、デフォルト MBean をクリックします。属性の値を変更するだけなく、MBean でメソッドを呼び出すこともできます。Operations タブをクリックし、name パラメーターに org.hibernate と入力して addLoggerMBean ボタンをクリックしてください。この操作によって、左側のツリーに新しい MBean が表示されます。

新たに追加された org.hibernate MBean をクリックして、priority 属性を DEBUG に変更します (図 9 を参照)。


図 9. org.hibernate MBean での priority 属性の変更

Web ブラウザーに戻ってホーム・リンクをクリックし、AirportMappingController をもう一度クリックします。すると、長々と続く DEBUG ログ・ステートメントが表示されます (リスト 10 を参照)。


リスト 10. Hibernate の log4j 出力

[DEBUG] 10:05:52 (AbstractBatcher.java:logOpenPreparedStatement:366)
about to open PreparedStatement (open PreparedStatements: 0, globally: 0)

[DEBUG] 10:05:52 (ConnectionManager.java:openConnection:421)
opening JDBC connection

[DEBUG] 10:05:52 (AbstractBatcher.java:log:401)
select this_.airport_id as airport1_0_0_, this_.locid as locid0_0_, 
this_.latitude as latitude0_0_, this_.longitude as longitude0_0_, 
this_.airport_name as airport5_0_0_, this_.state as state0_0_ 
from usgs_airports this_ limit ?

[DEBUG] 10:05:52 (AbstractBatcher.java:logOpenResults:382)
about to open ResultSet (open ResultSets: 0, globally: 0)

[DEBUG] 10:05:52 (Loader.java:getRow:1173)
result row: EntityKey[AirportMapping#1]

[DEBUG] 10:05:52 (Loader.java:getRow:1173)
result row: EntityKey[AirportMapping#2]


Hibernate の DEBUG 出力をスクロールしてください。データベースからデータが取り出されて Bean の ArrayList に変換されるときの動作内容が、ステップバイステップで詳細に示されています。


Spring Bean ビルダーの使用

resources.xml で JMX を構成する方法がわかったところで、今度は新たな方法を追加します。Grails が Spring 構成をサポートするために使用するファイルは、resources.groovy です。grails-app/conf/spring/resources.xml を resources.xml.old にリネームし、resources.groovyに、リスト 11 に記載するコードを追加してください。


リスト 11. Bean ビルダーを使用した Spring の構成

import org.springframework.jmx.support.MBeanServerFactoryBean
import org.springframework.jmx.export.MBeanExporter
import org.apache.log4j.jmx.HierarchyDynamicMBean

beans = {
  log4jBean(HierarchyDynamicMBean)
  
  mbeanServer(MBeanServerFactoryBean) {
    locateExistingServerIfPossible=true
  }
  
  exporter(MBeanExporter) {
    server = mbeanServer
  	beans = ["log4j:hierarchy=default":log4jBean]
  }    
}

ご覧のように、Spring Bean は XML ではなく Groovy コードで構成されています。Groovy の MarkupBuilder の動作は、「Grails とレガシー・データベース」、それに「RESTful な Grails」でも説明しました。今回はこのテーマを多少変更します。つまり、Bean ビルダーが Spring 構成の Bean を具体的に定義するようにします。

Grails と JConsole をリブートして、XML 構成との違いが何もないことを確認してください。

XML 方言を使用して Spring を構成すれば、Web のさまざまな知恵を簡単に利用することができます。つまり、さまざまなソースからスニペットをコピー・アンド・ペーストできるということです。しかし、Bean ビルダー方言を使用したほうが、Grails での残りの構成に調和します。皆さんはこれまでの Grails の経験のなかで、数例を挙げるだけでも DataSource.groovy、Config.groovy、BootStrap.groovy、Events.groovy を見てきました。構成をコードで行うということは、実行環境に応じて条件付きで MBean を公開するなどの動作が可能になるということです。

一例として、リスト 12 に log4jBean を本番環境では公開し、開発では隠す方法を説明します。


リスト 12. JMX Bean の条件付き公開

import org.springframework.jmx.support.MBeanServerFactoryBean
import org.springframework.jmx.export.MBeanExporter
import org.apache.log4j.jmx.HierarchyDynamicMBean
import grails.util.GrailsUtil

beans = {
  log4jBean(HierarchyDynamicMBean)
  
  mbeanServer(MBeanServerFactoryBean) {
    locateExistingServerIfPossible=true
  }
  
  switch(GrailsUtil.environment){
    case "development":
    break
    
    case "production":
      exporter(MBeanExporter) {
        server = mbeanServer
      	beans = ["log4j:hierarchy=default":log4jBean]
      }        
    break
  }
}

grails run-app を実行して、JConsole で log4j MBean が開発モードでは表示されないことを確認してください。次に、grails prod run-app を実行すると (または、grails war で WAR ファイルを任意のアプリケーション・サーバーにデプロイすると)、JConsole が再起動されるまで MBean は待機することになります。


Groovy での JMX

最後に説明するのは、JMX MBean をプログラムによって調整する方法です。JConsole は優れた GUI ですが、Groovy スクリプトからの変更が可能であれば、さらに素晴らしい GUI になります。

まず、testJmx.groovy という名前のファイルを作成し、リスト 13 のコードを追加します。


リスト 13. Groovy でのリモート JMX エージェントの呼び出し

import javax.management.MBeanServerConnection
import javax.management.remote.JMXConnectorFactory
import javax.management.remote.JMXServiceURL

def agentUrl = "service:jmx:rmi:///jndi/rmi://localhost:9004/jmxrmi"
def connector = JMXConnectorFactory.connect(new JMXServiceURL(agentUrl))
def server = connector.mBeanServerConnection 

println "Number of registered MBeans: ${server.mBeanCount}"

println "\nRegistered Domains:"
server.domains.each{println it}

println "\nRegistered MBeans:"
server.queryNames(null, null).each{println it}

Grails が実行中であれば、リスト 14 の内容が出力されます。


リスト 14. testJmx.groovy スクリプトによる出力

$ groovy testJmx.groovy 
Number of registered MBeans: 20

Registered Domains:
java.util.logging
JMImplementation
java.lang
log4j

Registered MBeans:
java.lang:type=MemoryManager,name=CodeCacheManager
java.lang:type=Compilation
java.lang:type=GarbageCollector,name=Copy
java.lang:type=MemoryPool,name=Eden Space
log4j:appender=stdout
java.lang:type=Runtime
log4j:hierarchy=default
log4j:logger=root
log4j:appender=stdout,layout=org.apache.log4j.PatternLayout
java.lang:type=ClassLoading
java.lang:type=MemoryPool,name=Survivor Space
java.lang:type=Threading
java.lang:type=GarbageCollector,name=MarkSweepCompact
java.util.logging:type=Logging
java.lang:type=Memory
java.lang:type=OperatingSystem
java.lang:type=MemoryPool,name=Code Cache
java.lang:type=MemoryPool,name=Tenured Gen
java.lang:type=MemoryPool,name=Perm Gen
JMImplementation:type=MBeanServerDelegate

注意

testJmx.groovy スクリプトは、リスト 15 のような groovy.lang.MissingMethodException をスローする場合があります。


リスト 15. 考えられる JMX 例外

Caught: groovy.lang.MissingMethodException: No signature of method: 
 javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection.queryNames() 
 is applicable for argument types: (java.lang.String, null) 

このような例外がスローされた場合は、$GROOVY_HOME/lib から mx4j-3.0.2.jar を削除してください。このファイルは、1.4 JDK に JMX サポートを提供するために Groovy ディストリビューションに含まれているものですが、Java プラットフォームの最近のバージョンとは競合します。

このスクリプトが面白くなってくるのは、connector.mBeanServerConnection の呼び出しによって javax.management.MBeanServer が返されるところからです (Java での getFoo() メソッド呼び出しは、Groovy では foo に短縮できることを思い出してください)。server.mBeanCount の呼び出しによって登録済み MBean の数が返され、server.domains の呼び出しによってドメイン名の String[] が返されます。ドメイン名は MBean ID の最初の部分で、名前と値のペアからなるカンマ区切りリストによって名前が完全修飾されます。そして server.queryNames(null, null) の呼び出しによって、登録済み MBean のすべてからなる Set が返されます (MbeanServer クラスに用意されているメソッドについての詳細は「参考文献」を参照してください)。

特定の MBean を取得するには、上記のスクリプトの最後にリスト 16 のコードを追加します。


リスト 16. MBean の取得

println "\nHere is the Runtime MBean:"
def mbean = new GroovyMBean(server, "java.lang:type=Runtime")
println mbean

MBean サーバーに接続して MBean の名前がわかれば、新しい GroovyMBean をたった 1 行で取得することができます。リスト 17 に、このスクリプトの出力を記載します。


リスト 17. GroovyMBean の出力

Here is the Runtime MBean:
MBean Name:
  java.lang:type=Runtime
  
Attributes:
  (r) javax.management.openmbean.TabularData SystemProperties
  (r) java.lang.String VmVersion
  (r) java.lang.String VmName
  (r) java.lang.String SpecName
  (r) [Ljava.lang.String; InputArguments
  (r) java.lang.String ManagementSpecVersion
  (r) java.lang.String SpecVendor
  (r) long Uptime
  (r) long StartTime
  (r) java.lang.String LibraryPath
  (r) java.lang.String BootClassPath
  (r) java.lang.String VmVendor
  (r) java.lang.String ClassPath
  (r) java.lang.String SpecVersion
  (r) java.lang.String Name
  (r) boolean BootClassPathSupported

記事の最初のほうに出てきた InputArguments を覚えていますか?これらの入力引数はすべて JVM に渡される -D パラメーターに含まれていて、リモート JMX エージェントと本当に接続しているかどうかを確認するために使用しました。さらに 2 行のコード (リスト 18 を参照) を追加して、String[] を出力します。


リスト 18. ランタイム MBean からの InputArguments の取得

println "\nHere are the InputArguments:"
mbean.InputArguments.each{println it}

リスト 19 の出力を見ると、完全に一周したことがわかります。


リスト 19. InputArguments の表示

Here are the InputArguments:
-Xserver
-Xmx512M
-Dcom.sun.management.jmxremote
-Djava.rmi.server.hostname=localhost
-Dcom.sun.management.jmxremote.port=9004
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dprogram.name=grails
-Dgroovy.starter.conf=/opt/grails/conf/groovy-starter.conf
-Dgrails.home=/opt/grails
-Dbase.dir=.
-Dtools.jar=/Library/Java/Home/lib/tools.jar

GroovyMBean についての詳細は、「参考文献」を参照してください。


まとめ

Grails はエンタープライズに対応します。Grails では、JMX、Spring、log4j などの一般的なエンタープライズ・ライブラリーを使用することができます。なぜなら、その見かけとは裏腹に、Grails で行っているのは従来の Java 開発に変わりないからです。

今回の記事で、ほぼ 1 年かけて Trip Planner アプリケーションについて探ってきたことになりますが、連載記事を通じて一貫してこの同じアプリケーションを扱ってきたのは、Grails のコアとなる機能に焦点を置きたかったためです。来年の記事でもこの Grails のコアとなる機能に焦点を置くという主義を崩さないつもりですが、それと同時に、視野を広げて多種多様な Grails アプリケーションを取り上げるつもりでもいます。

例えば、来月は新しいブログ・システムを紹介します。記事では新規 Grails アプリケーションをブートストラップする方法について簡単に復習しますが、このアプリケーションは今まで使用していた素材から新しく作り直したものです。Grails の RESTful な側面を再び取り上げますが、今度は完全な Atom インフラストラクチャーをセットアップするというコンテキストにします。使用するのは同じく JSON と Ajax ですが、今度はカレンダーとタグ・クラウドを有効にします。そして数か月後には、まったく別の新しい構想を展開する予定です。

次々と誕生する新たな Web サイトでは、Grails が主流の技術として受け入れられています。完成度を極めた Web フレームワークでは、Grails をさまざまな方法で使用しています。連載「Grails をマスターする」では来年の記事をとおして、Grails で実現可能な多様な Web サイトを紹介していく予定です。それまでは、Grails を楽しみながらマスターしてください。


参考文献

学ぶために

  • 連載「Grails をマスターする」: この連載の他の記事を読んで、Grails とこのフレームワークを使って実現可能なすべての内容をよく理解してください。

  • Grails: Grails の Web サイトにアクセスしてください。

  • Groovy Recipes』(Scott Davis 著、Pragmatic Programmers、2007年): Scott Davis の最新の著作で Groovy と Grails の詳細を学んでください。

  • Grails Framework Reference Documentation: Grails のバイブルとなります。

  • Java の理論と実践: JMX を使ったアプリケーションのインスツルメンテーション」(Brian Goetz 著、developerWorks、2006年9月): JVM、そして JVM を使用するクラスに可視性をもたらす方法について詳しく学んでください。

  • Monitoring and Management Using JMX: Sun による JMX モニターについてのガイドを参照してください。

  • log4j によって可能になるログの制御」(Ceki Gulcu 著、developerWorks、2001年1月): log4j プロジェクトの創始者が、log4j API、その固有の機能、およびその設計理論について説明します。

  • PatternLayout: このクラスに関する Javadoc を調べてください。

  • MBeanServer: MBeanServer クラスで使用できるメソッドについて詳しく学んでください。

  • Groovy and JMX: GroovyMBean についての詳細を調べてください。

  • Grails Bean Builder: Spring Bean をプログラムでビルドしてください。

  • 連載「実用的な Groovy」: developerWorks のこの連載記事では、実用的な Groovy の使用方法を探り、それぞれの方法をいつ、どんな場合に適用するかを解説しています。

  • Groovy: Groovy の Web サイトで、このプロジェクトの詳細を学んでください。

  • AboutGroovy.com: Groovy に関する最新のニュースと記事へのリンクが記載されています。

  • technology bookstore: この記事で紹介した技術やその他の技術に関する本を参照してください。

  • developerWorks Java technology ゾーン: Java プログラミングのあらゆる側面を網羅した記事が豊富に用意されています。

製品や技術を入手するために

  • Grails: Grails の最新リリースをダウンロードしてください。

議論するために

著者について

Scott Davis

Scott Davis は国際的に知られた著者、講演者、そしてソフトウェア開発者です。彼の著書には、『Groovy Recipes: Greasing the Wheels of Java』、『GIS for Web Developers: Adding Where to Your Application』、『The Google Maps API』、『JBoss At Work』などがあります。

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


developerWorks: サイン・イン


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。 プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。 お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

表示名をお選びください

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

(半角英数字で3文字以上31文字以下にする必要があります)


「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


この記事を評価する

コメント

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology, Web development, Open source
ArticleID=367279
ArticleTitle=Grails をマスターする: エンタープライズでの Grails
publish-date=12162008
author1-email=scott@aboutgroovy.com
author1-email-cc=