目次


Groovy 流の Spring

第 1 回 統合の基本

Groovy が Spring ベースのアプリケーションに柔軟性をもたらす仕組み

Comments

コンテンツシリーズ

このコンテンツは全#シリーズのパート#です: Groovy 流の Spring

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:Groovy 流の Spring

このシリーズの続きに乞うご期待。

Spring 2.0 では、動的言語を Spring ベースのアプリケーションに統合するためのサポートを導入しています。これにより、Spring では設定を追加しなくても、そのままで Groovy、JRuby、BeanShell をサポートするようになっています。アプリケーションのなかで Groovy や JRuby、あるいは Spring によってサポートされる他の言語 (もちろん、Java™ 言語が含まれます) で作成した部分は、Spring アプリケーションにシームレスに統合されます。アプリケーションの残りのコードが個々の Spring Bean の実装言語を認識したり、考慮したりする必要はありません。

Spring が動的言語をサポートするということは、ストリングを追加しなくても、アプリケーションには柔軟性がもたらされ、しかも動的振る舞いも可能になるということであり、柔軟性と動的振る舞いの両方を同時に実現できるのです。この連載の第 1 回では、Spring と Groovy を併用する方法、そしてこの強力な組み合わせによってアプリケーションにもたらされる興味深い追加の機能について説明します。例えば、ビジネス・ロジックのごく小さなチャンクや、アプリケーションが送信する E メール・メッセージに含まれるテキスト、さらにはアプリケーションが生成する PDF のフォーマットとレイアウトを頻繁に変更しなければならないとします。従来のアプリケーション・アーキテクチャーでは、この類の変更を行うにはアプリケーションを完全に再デプロイしなければなりません。しかし Spring では、Groovy がサポートされているため、このような変更をデプロイ済みアプリケーションに加えて即時に適用することが可能です。この記事では、動的言語のサポートがアプリケーションにもたらす利点だけでなく、発生する可能性のある問題についても説明します。記事に記載するすべてのサンプルは、その完全なソース・コードを「ダウンロード」セクションからダウンロードすることができます。

Spring の動的言語サポート

動的言語をサポートすることによって、Spring は Java 中心のアプリケーション・フレームワークから JVM 中心のアプリケーション・フレームワークに変わりました。今や、Spring は Java 開発を容易にするだけではありません。Spring がサポートおよび促進する階層型アーキテクチャーには、静的言語と動的言語で作成されたコードの両方を簡単に組み込めるため、JVM の開発も容易になります。Spring をすでに使い慣れている開発者にとっても、違和感はまったくないはずです。Groovy などの柔軟な動的言語を使用しながらも、制御の反転 (IoC) や依存性注入、アスペクト指向プログラミング (AOP)、宣言型トランザクション区分、Web フレームワークとデータ・アクセス・フレームワークの統合、リモーティングなどの Spring の機能をすべて今まで通り使えるからです。

Spring は動的言語の統合をサポートする手段として、ScriptFactory インターフェースと ScriptSource インターフェースを使用します。ScriptFactory インターフェースはスクリプト化した Spring Bean を構成および作成するためのメカニズムを定義します。理論的には、JVM 上で動作するあらゆる言語をサポートできるので、お好みの特定の言語を対象に独自の実装を作成することも可能です。もう一方の ScriptSource は、Spring が実際のスクリプト・ソース・コードにアクセスする方法、例えばファイル・システムや URL などを定義します。Groovy 言語の統合は、ScriptFactoryGroovyScriptFactory 実装によってサポートされます。

なぜ Groovy なのか

Groovy の公式サイトによると、Groovy は「Java 仮想マシンを対象としたアジャイルな動的言語」であり、「Java の長所に基づいて作成されている一方、Python、Ruby、Smalltalk などの言語から発想を得た強力な追加機能も備わっています」。この追加機能とは、動的型付け、クロージャー、そしてメタプログラミングのサポートなどです(「参考文献」を参照)。本格的オブジェクト指向プログラミング言語である Groovy は、そのままオブジェクト指向プログラミング言語として使うこともできれば、純粋なスクリプト言語として使うこともできます。私にとっての Groovy は、作成したくないコードをすべて省略できるだけでなく、クロージャーや動的言語が持つその他の機能を使える Java 言語だと言えます。

Spring の動的言語サポートで使用する言語としては、Groovy が最も有力な候補となります。その理由としては、Groovy は JVM 専用に設計されていること、そして Java との密接な統合が考慮されているため Groovy と Java コードを共存させるのが容易であることがあります。さらに、その Java に似た構文は Java 開発者にとって違和感なく使用することができます。

ここからはいよいよ、Groovy コードを Spring ベースのアプリケーションに統合する方法に目を向けます。

Groovy 流の Spring Bean

Spring アプリケーションで Groovy Bean を使用するのは、Java Bean を使用するのとまったく同じく簡単です (ただし後で説明するように、構成の点では使用できるオプションが増えます)。まず始めに必要な作業は、Groovy Bean が従う規約としての役割を果たすインターフェースを定義することです。インターフェースの定義は絶対に必要というわけではありませんが、ほとんどの Spring アプリケーションでは、アプリケーション・コンポーネント間の相互作用と依存関係を具体的実装クラスではなくインターフェースで定義することによって、疎結合を促すとともにテストしやすくしています。

一例として、Invoice オブジェクトから PDF を生成する方法を定義するインターフェースがあるとします (リスト 1 を参照)。

リスト 1. PdfGenerator インターフェース
public interface PdfGenerator {
    byte[] pdfFor(Invoice invoice);
}

この PdfGenerator インターフェースが、Groovy 実装クラスの規約としての役割を果たします。Groovy クラスは Java クラスと同じようにしてインターフェースを実装できるので、インターフェースを実装するのは至って簡単です。リスト 2 に記載する PdfGenerator の Groovy 実装は、iText ライブラリー (「参考文献」を参照) を使用して実際の PDF 生成を行い、PDF のコンテンツが含まれるバイト配列を返します。

リスト 2. GroovyPdfGenerator
class GroovyPdfGenerator implements PdfGenerator {

    String companyName

    public byte[] pdfFor(Invoice invoice) {
        Document document = new Document(PageSize.LETTER)
        ByteArrayOutputStream output = new ByteArrayOutputStream()
        PdfWriter.getInstance(document, output)
        document.open()
        Font headerFont = new Font(family: Font.HELVETICA, size: 24.0, style: Font.ITALIC)
        document.add(new Paragraph("$companyName", headerFont))
        document.add(new Paragraph("Invoice $invoice.orderNumber"))
        document.add(new Paragraph("Total amount: \$ ${invoice.total}"))
        document.close()
        output.toByteArray()
    }
}

GroovyPdfGenerator が活躍する準備はこれで整いました。このインターフェースは、companyName という名前のストリング・プロパティーを定義しています。生成された PDF 版の納品書では、注文番号と合計に併せて、このプロパティーが使用されます。この時点で、GroovyPdfGenerator を Spring アプリケーションに統合する準備はできたことになります。Java 言語を使って作成した Bean は .class ファイルにコンパイルしなければなりませんが、Groovy ベースの Bean を使用する場合には、いくつかの選択肢があります。

  • Groovy クラスを通常の Java クラス・ファイルにコンパイルする
  • Groovy クラスまたはスクリプトを .groovy ファイルに定義する
  • Groovy スクリプトを Spring 構成ファイルにインラインで書き込む

上記の選択肢のうち、Groovy Bean にどれを使用するかによって、Spring アプリケーションのコンテキストで Groovy Bean を定義し、構成する方法をさまざま方法の中から選択することができます。次のセクションでは、これらの構成上の選択肢のそれぞれについて説明します。

Groovy Bean の構成

一般に、Java コードで作成された Spring Bean を構成するには XML を使用するか、または Spring 2.5 で行っているように (「参考文献」を参照) アノテーションを使用します。アノテーションを使用すると、XML 構成は大幅に削減されることになります。Groovy Bean を構成するときには、コンパイル済み Groovy クラスを使用するか、.groovy ファイルに定義した Groovy クラスを使用するかによって、指定できる選択肢は変わってきます。肝心な点は、Groovy を使用して Bean を実装するには、Java プログラミングでの通常の方法と同じく Groovy Bean をコンパイルすることも、Groovy Bean をクラスまたはスクリプトとして .groovy ファイルに実装し、Spring にアプリケーション・コンテキストを作成する時点でコンパイルさせることもできるということです。

Bean を .groovy ファイルに実装することにした場合には、コンパイル作業は不要になります。Spring がファイルを読み取ってスクリプトのソース・コードを取得し、実行時にコンパイルして、アプリケーション・コンテキストで使用できるようにするからです。.groovy ファイルは、必ずしもアプリケーションの JAR や WAR ファイルにデプロイする必要はありません。ファイル・システムのどこか、あるいは URL から提供することもできます。そのため Bean を直接コンパイルするよりも、.groovy ファイルに Bean を実装する方法のほうが、融通が効くことになります。

この後、さまざまな構成上の選択肢がどのように機能するかを説明します。Groovy クラスの中で定義し、独自のビルド・プロセスの一環としてコンパイルする場合の Bean と、.groovy スクリプトに定義した場合の Bean との違いを念頭に置いておいてください。

コンパイル済み Groovy クラスを構成する場合

すでにコンパイルされている Groovy Bean を .class ファイルに含めるように構成する方法は、Java ベースの Bean を構成する方法とまったく同じです。例えば groovyc コンパイラーを使って GroovyPdfGenerator をコンパイルしたとすると、この Bean はリスト 3 のように通常の Spring XML 構成を使って定義することができます。

リスト 3. XMLを使用したプリコンパイル済み GroovyPdfGenerator の構成
<bean id="pdfGenerator" class="groovierspring.GroovyPdfGenerator">
    <property name="companyName" value="Groovy Bookstore"/>
</bean>

リスト 3 の構成は、いつもながらの単純な Spring Bean 定義です。Bean が Groovy で実装されているという事実は重要ではありません。Spring アプリケーションのコンポーネントのうち、pdfGenerator Bean が含まれる他のすべてのコンポーネントは、実装の詳細や言語を認識したり、考慮したりすることなく、この Bean を使用することができます。また、Bean にプロパティーを設定するにも、通常と同じく <property> 要素を使用することができます (Spring 2.0 ではより簡潔にプロパティーを定義する方法として p という名前空間を導入していますが、私は読みやすいという理由で <property> 要素を引き続き使用しました。これは、まったくの好みの問題です)。

Spring 2.5 以降を使用している場合には、GroovyPdfGenerator のアノテーション・ベースの構成を使うこともできます。その場合、XML アプリケーションのコンテキストに実際に Bean を定義するのではなく、クラスにステレオタイプのアノテーション、@Component を設定します (リスト 4 を参照)。

リスト 4. @Component による GroovyPdfGenerator へのアノテーション付加
@Component("pdfGenerator")
class GroovyPdfGenerator implements PdfGenerator {
    ...
}

上記のようにアノテーションを設定した上で、Spring アプリケーション・コンテキストの XML 構成でアノテーション構成とコンポーネント・スキャンを有効にします (リスト 5 を参照)。

リスト 5. Spring アノテーション構成とコンポーネント・スキャンの有効化
<context:annotation-config/>
<context:component-scan base-package="groovierspring"/>

XML とアノテーションのどちらを使用して構成するかに関わらず、コンパイル済み Groovy Bean の構成は、通常の Java ベースの Bean を構成する場合とまったく同じであることを忘れないでください。

Groovy スクリプトから Bean を構成する場合

.groovy スクリプトから Groovy Bean を構成する方法は、コンパイル済み Groovy Bean を構成する場合とはかなり異なります。話が一気に面白くなってくるのは、ここからです。Groovy スクリプトを Bean に変換するためのメカニズムでは、Groovy スクリプトを読み取り、コンパイルし、コンパイルしたスクリプトを Spring アプリケーションのコンテキストで Bean として使用できるようにする必要があります。最初のステップでは、表面上は GroovyScriptFactory の型を持ち、Groovy スクリプトのロケーションを指す Bean を定義します (リスト 6 を参照)。

リスト 6. GroovyScriptFactory Bean の定義
<bean id="pdfGenerator"
      class="org.springframework.scripting.groovy.GroovyScriptFactory">
    <constructor-arg value="classpath:groovierspring/GroovyPdfGenerator.groovy"/>
    <property name="companyName" value="Groovier Bookstore"/>
</bean>

上記のリストでは、pdfGenerator Bean が GroovyScriptFactory として定義されています。<constructor-arg> 要素は、構成中の Groovy スクリプトのロケーションを定義する要素です。この要素はコンパイルされた Groovy クラスではなく、Groovy スクリプトを指すことに注意してください。スクリプト化されたオブジェクトにプロパティーを設定する構文は、Spring Bean を定義するときに通常使用する構文と同じです。リスト 6 の <property> 要素は、ご想像のとおり、companyName プロパティーを設定しています。

GroovyPdfGenerator.groovy スクリプトには、インターフェースを実装するクラスが少なくとも 1 つは含まれていなければなりません。通常は、一般的な Java プラクティスに従って、.groovy ファイルごとに 1 つの Groovy クラスを定義するのが最善の策ですが、作成する Bean の型を判断するためのロジックをスクリプト内に実装することもできます。例えば、GroovyPdfGenerator.groovy に PdfGenerator インターフェースの2 種類の実装を定義し、スクリプト内で直接、どちらの実装を返すかを判断するロジックを実行するなどです。リスト 7 では、2 種類の PdfGenerator 実装を定義し、システム・プロパティーに応じて使用する実装を選択しています。

リスト 7. Groovy スクリプト内での複数のクラス定義
class SimpleGroovyPdfGenerator implements PdfGenerator {
    ...
}

class ComplexGroovyPdfGenerator implements PdfGenerator {
    ...
}

def type = System.properties['generatorType']
if (type == 'simple')
    return new SimpleGroovyPdfGenerator()
}
else {
    return new ComplexGroovyPdfGenerator()
}

上記のスニペットに示されているように、スクリプト化した Bean を使って、システム・プロパティーに応じて異なる実装を選択することができます。generatorType システム・プロパティーが simple に設定されている場合、スクリプトは SimpleGroovyPdfGenerator を作成して返し、そうでない場合には ComplexGroovyPdfGenerator を返します。単純な実装と複雑な実装はどちらも PdfGenerator インターフェースを実装するため、Spring アプリケーション内部の pdfGenerator Bean を使用するコードは、実際の実装内容を認識することも、考慮することもありません。

注目すべき点は、Bean がスクリプトから返されるとしても、リスト 6 のようにプロパティーを設定できることです。つまり、スクリプトが ComplexGroovyPdfGenerator を返すと、その Bean にはcompanyName プロパティーが設定されます。このように、複数の実装を定義できるようにする一層の柔軟性は必要ないというのであれば、リスト 8 のように、Groovy スクリプト・ファイルに 1 つのクラスを定義するだけで構いません。この場合、Spring はこの唯一のクラスを検出して自動的にインスタンス化します。

リスト 8. 標準的な Groovy スクリプトの実装
class GroovyPdfGenerator implements PdfGenerator {
    ...
}

上記のリストを見たところで、リスト 6 ではなぜ、Bean を GroovyScriptFactory として定義しているのか疑問に思うかもしれません。その理由は、Spring はスクリプト化したオブジェクトを作成する手段として ScriptFactory 実装 (この例の場合は Groovy ファクトリー) を ScriptFactoryPostProcessor Beanと組み合わせて使用するからです。このポストプロセッサー Bean が、ファクトリー Bean をファクトリーによって作成された実際のオブジェクトに置き換えます。リスト 9 に、ポストプロセッサー Bean を加えるための追加構成を記載します。

リスト 9. ScriptFactoryPostProcessor Bean の定義
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>

Spring はアプリケーション・コンテキストをロードすると、まずファクトリー Bean (例えば、GroovyScriptFactory Bean) を作成します。すると、ScriptFactoryPostProcessor Bean がすべてのファクトリー Bean を検索して、スクリプト化された実際のオブジェクトに置き換えます。例えば、リスト 6リスト 9 に記載した構成では、名前が pdfGenerator で、型が groovierspring.GroovyPdfGenerator の Bean が作成されることになります (Spring でデバッグ・レベルのロギングを有効にしてアプリケーション・コンテキストの開始の様子を観察すると、Spring はまず始めに scriptFactory.pdfGenerator という名前のファクトリー Bean を作成し、その後、ScriptFactoryPostProcessor がこのファクトリー Bean から pdfGenerator Bean を作成することがわかります)。

スクリプト化した Groovy Bean を GroovyScriptFactoryScriptFactoryPostProcessor を使って構成する上での下位レベルの詳細がわかったところで、これと同じ結果を達成する遙かに単純でわかりやすい方法を紹介することにしましょう。Spring には、スクリプト化された Bean を作成することを目的とした lang XML スキーマが用意されています。リスト 10 では、この lang スキーマを使用して pdfGenerator Bean を定義します。

リスト 10. <lang:groovy> を使用したスクリプト化 Bean の定義
<lang:groovy id="pdfGenerator"
             script-source="classpath:groovierspring/GroovyPdfGenerator.groovy">
    <lang:property name="companyName" value="Really Groovy Bookstore"/>
</lang:groovy>

上記のコードが作成する pdfGenerator Bean は、リスト 6リスト 9 での詳細な構成と同じものですが、このコードのほうがわかりやすく簡潔で、その目的はより明確になっています。<lang:groovy> の Bean 定義には、script-source 属性が必要です。この属性が、Spring に Groovy スクリプトのソース・コードを見つける方法を指示します。さらに、スクリプト化された Bean には <lang:property> 要素を使用してプロパティーを設定することもできます。このように、<lang:groovy> を使用して Groovy ベースの Bean を定義する方法は、誰が読んでもわかりやすい Spring 構成にできる、より良い選択肢となります。

インライン Groovy スクリプトを構成する場合

完全を期して、Spring では Bean 定義に直接 Groovy スクリプトを書き込むという方法もサポートしていることを言い添えておきます。リスト 11 は、インライン・スクリプトを使用して pdfGenerator Bean を作成する例です。

リスト 11. インラインによるスクリプト化 Bean の定義
<lang:groovy id="pdfGenerator">
    <lang:inline-script>
        <![CDATA[
        class GroovyPdfGenerator implements PdfGenerator {
            ...
        }
        ]]>
    </lang:inline-script>
    <lang:property name="companyName" value="Icky Groovy Bookstore"/>
</lang:groovy>

上記のスニペットで pdfGenerator Bean を定義するために使用しているのは、<lang:groovy> と、クラスを定義する Groovy スクリプトが含まれる <lang:inline-script> タグです。プロパティーは前と同じく、<lang:property> を使用して設定することができます。ご想像の通り、私はこのように XML 構成ファイル内にスクリプト化した Bean を定義することはお薦めしません (どんなタイプのコードでも、インラインで XML ファイル内に含めるという方法はお薦めできません)。

Grails Bean Builder を使用して Bean を構成する場合

Grails Web フレームワークは、内部で Spring に依存します。Grails には、Groovy コードを使用して Spring Bean をプログラムで定義できるようにする優れた機能、Bean Builder があります (「参考文献」を参照)。このように Bean をプログラムで定義するとなると、Bean 定義スクリプトにロジックを組み込むこともできます。これは XML には不可能な芸当なので、プログラムによる Bean の定義は、XML 構成よりも優れた柔軟性をもたらす可能性があるということです。Bean Builder では、コンパイル済み Groovy クラスの Bean 定義を作成することも、スクリプト化された Groovy Bean の Bean 定義を作成することもできます。リスト 12 では、コンパイル済み Groovy クラスを使用して pdfGenerator Bean を定義しています。

リスト 12. Bean Builder によるコンパイル済み Groovy Bean の定義
def builder = new grails.spring.BeanBuilder()
builder.beans {
    pdfGenerator(GroovyPdfGenerator) {
        companyName = 'Compiled BeanBuilder Bookstore'
    }
}
def appContext = builder.createApplicationContext()
def generator = context.pdfGenerator

リスト 12 のコードではまず BeanBuilder をインスタンス化し、それから Bean を作成するためのメソッドを呼び出します。それぞれのメソッド呼び出しとオプションのクロージャー引数によって Bean が定義され、Bean プロパティーが設定されます。例えば、pdfGenerator(GroovyPdfGenerator) は、pdfGenerator という名前で、型が GroovyPdfGenerator の Bean を定義し、クロージャー内部のコードが companyName プロパティーを設定します。もちろん、beans クロージャー内部には複数の Bean を定義することができます。

Bean Builder を使用する場合には、コンパイル済み Groovy クラスからではなく、Groovy スクリプトから Bean を作成することもできます。ただし、Bean Builder には <lang:groovy> 構成で目にしたシンタックス・シュガーに相当するものはないため、Bean を GroovyScriptFactory として定義し、さらに ScriptFactoryPostProcessor Bean を作成する必要が出てきます。リスト 13 は、Bean Builder を使用してスクリプト化 Groovy Bean を構成する場合の一例です。

リスト 13. Bean Builder によるスクリプト化 Groovy Bean の定義
def builder = new grails.spring.BeanBuilder()
builder.beans {
    pdfGenerator(GroovyScriptFactory,
                'classpath:groovierspring/GroovyPdfGenerator.groovy') {
        companyName = 'Scripted BeanBuilder Bookstore'
    }
    scriptFactoryPostProcessor(ScriptFactoryPostProcessor)
}
def appContext = builder.createApplicationContext()
def generator = context.pdfGenerator

リスト 13 のコードは、論理的にはリスト 6リスト 9 に記載した XML 構成と同じですが、リスト 13 では言うまでもなく、Groovy コードを使用して Bean を定義しています。pdfGenerator Bean を定義するために、リスト 13 では型を GroovyScriptFactory に指定しています。2 番目の引数はスクリプト・ソースのロケーションを指定して、前と同じくクロージャー内部に companyName プロパティーを設定します。さらに、ScriptFactoryPostProcessor 型の scriptFactoryPostProcessor という名前の Bean も定義しています。これによって、ファクトリー Bean は実際のスクリプト化されたオブジェクトに置き換えられることになります。

どの構成オプションが最適か

これまで、Bean がコンパイル済みであるか、スクリプト化されているかに関わらず、Groovy ベースの Bean を構成するさまざまな方法を説明してきました。アプリケーションの主要言語として Java 言語に代わって Groovy を使用するだけであれば、Bean を構成する方法は、Java ベースの Bean を構成する場合と何の違いもありません。コンパイル済み Groovy クラスには XML による構成またはアノテーション・ベースの構成のどちらでも使用することができます。

スクリプト化された Groovy オブジェクトの場合、その構成方法は何通りかあるにせよ、GroovyScriptFactoryScriptFactoryPostProcessor を使用して構成する場合や <lang:inline-script> を使用して構成する場合とは対照的に、<lang:groovy> を使用して構成するのが最も簡潔な方法となるだけでなく、その目的も最も明確になります。

Grails Bean Builder を使用する方法についても説明しました。Bean Builder は、大抵の Spring アプリケーションが使用する方法とはまったく違った方法で、Spring アプリケーション・コンテキストを作成します。Bean をすべて Groovy で作成し、ロジックを Bean ビルド・プロセスに追加したいのであれば、Bean Builder がその目的を十分にかなえるはずです。その一方、Bean Builder を使って Groovy Bean を定義するには、GroovyScriptFactoryScriptFactoryPostProcessor を使用して Bean を定義しなければならなくなります。

Groovy Bean の使用方法

Bean 構成とそのために使用可能なさまざまな選択肢は、この記事の説明ではそれほど厄介には思えなかったかもしれませんが、Groovy と Spring を統合する上での難しい部分です。一方、Spring アプリケーションで実際に Groovy Bean を使うのは簡単です。実のところ、Spring の動的言語サポートは、これらの Bean を使用していることをアプリケーション・コードに対してはまったくわからなくするため、アプリケーション・コードは実装の詳細を知ることも、考慮することもありません。Spring アプリケーションでのいつもの方法でアプリケーション・コードを作成すれば、依存性注入、AOP、そして多数のサード・パーティーのフレームワークとの統合など、Spring が一般に提供するすべての機能を利用することができます。

リスト 14 に示す単純な Groovy スクリプトは、XML 構成ファイルから Spring アプリケーション・コンテキストを作成し、PDF 生成 Bean を取得した後、それを使用して PDF 版の納品書を生成します。

リスト 14. スクリプトでの Groovy Bean の使用
def context = new ClassPathXmlApplicationContext("applicationContext.xml")
def generator = context.getBean("pdfGenerator")

Invoice invoice = new Invoice(orderNumber: "12345", orderDate: new Date())
invoice.lineItems = [
    new LineItem(quantity: 1, description: 'Groovy in Action (ebook)', price: 22.00),
    new LineItem(quantity: 1, description: 'Programming Erlang', price: 45.00),
    new LineItem(quantity: 2, description: 'iText in Action (ebook)', price: 22.00)
]

byte[] invoicePdf = generator.pdfFor(invoice)

FileOutputStream file = new FileOutputStream("Invoice-${invoice.orderNumber}.pdf")
file.withStream {
    file.write(invoicePdf)
}
println "Generated invoice $invoice.orderNumber"

リスト 14 に記載されている大部分のコードは、Spring の ApplicationContext の作成、納品書の作成、そして作成した納品書のファイルへの書き出しに関わるもので、pdfGenerator Bean を使って納品書を作成するためのコードはたった 1 行です。典型的な Spring アプリケーションでは、アプリケーションの開始時にアプリケーション・コンテキストを 1 度ブートすれば、コンポーネントでは Spring が提供する依存性を単純に使用するだけとなります。Spring Web アプリケーションでは、サーブレット・コンテキスト・リスナーを構成して、アプリケーションの開始時に Spring をブートさせることもできます。PDF 版納品書生成サービスの場合、リスト 15 のように定義することになります。

リスト 15. PDF ジェネレーターを利用する場合のサービス・クラス
@Service
public class InvoicePdfServiceImpl implements InvoicePdfService {

    @Autowired
    private PdfGenerator pdfGenerator;

    public byte[] generatePdf(Long invoiceId) {
        Invoice invoice = getInvoiceSomehow(invoiceId);
        return pdfGenerator.pdfFor(invoice);
    }

    // Rest of implementation...

}

リスト 15 の InvoicePdfServiceImpl クラスは、ここではたまたま PdfGenerator に依存する Java クラスとして実装されていますが、Groovy Bean として実装する場合でも、同じく簡単に実装することができます。GroovyPdfGenerator 実装をどのコンパイル済み Bean 構成またはスクリプト化 Bean 構成と一緒に使用するとしても、InvoicePdfServiceImpl はそのことを認識しません。つまり、Groovy Bean (あるいは、いずれかの動的言語の Bean) が使用されていることは、アプリケーション・コードにはわかりません。このことによる成果は、コンポーネント間の疎結合を実現できること、ユニット・テストが遙かに簡単になること、しかも作業に使用する最適な実装言語を任意に選んで使用できることです。

第 1 回のまとめ

第 1 回では、Groovy 言語の Bean を構成するさまざまな方法と、Spring ベースのアプリケーションでは、いかに簡単に Groovy Bean を使うことができるかを説明しました。コンパイル済み Groovy クラスは、Java クラスとまったく同じように使用することができます。また、スクリプト化された Groovy オブジェクトを構成するいくつかの方法についても説明しましたが、どの方法を選択するべきかは、アプリケーションで Groovy をどのように使用するかによって異なります。場合によっては、コンパイル済み Groovy Bean とスクリプト化された Groovy Bean を同じアプリケーションで組み合わせることも可能です。実際、お望みとあれば Java、Groovy、JRuby、および BeanShell のすべての Bean を同じアプリケーションで使用することもできますが、そうすることはお薦めしません。開発者としては、アプリケーションで複数の言語を使用することの利点と欠点を十分に考慮する必要があります。

Java 言語と比較した場合の Groovy の言語としての柔軟性は、Groovy クラスをコンパイルするだけにした場合でも、この言語を魅力的な選択肢にします。さらに、Spring ではスクリプト化された動的言語の Bean を統合できることが、Groovy を非常に有力な選択肢にしています。Groovy を統合すれば、スクリプト化された Bean にロジックを追加して一層優れた柔軟性をもたらすことができるからです。前にも説明したように、例えばロジックを追加すれば、アプリケーションの開始時にインスタンス化する Bean の型をビジネス・ロジックに基づいて決定することができます。あるいは、アプリケーションの CLASSPATH やファイル・システムに含まれてはいるものの、WAR ファイルにはパッケージ化されていない .groovy ファイルを使用して、その .groovy ファイルにスクリプト化したオブジェクトをデプロイするという方法で、Web アプリケーションを柔軟にデプロイすることも可能です。

これまで説明してきた内容は、いずれも Spring ツールキットに柔軟性と追加機能をもらたすものですが、Spring の動的言語サポートでおそらく最も魅力的な機能は、アプリケーションの実行中に動的言語スクリプトに加えられた変更をモニターして検出し、Spring アプリケーション・コンテキストのなかで変更された Bean を自動的にリロードする機能です。第 2 回では、実行時に変更できない Bean が含まれる静的構成を使用するよりも、遙かに柔軟性を高めるこの機能について徹底的に検討します。


ダウンロード可能なリソース


関連トピック

  • Spring Framework: Spring のホーム・ページです。
  • The Spring series」(Naveen Balani 著、developerWorks、2005年): Spring Framework について紹介している 4 回の連載記事です。
  • Spring 2.5 の新機能」(Mark Fisher 著、InfoQ、2007年11月): Spring Framework で行われた最新の改善内容について読んでください。
  • Spring Dynamic Language Support」: Spring リファレンス・ガイドのこの章で、Spring での動的言語サポートについて説明しています。
  • Programming Groovy』(Venkat Subramaniam 著、The Pragmatic Programmers、2008年): この本には、Groovy のメタプログラミング機能を使用する上での多くのアドバイスが記載されています。
  • Grails Bean Builder: Spring Bean をプログラムでビルドしてください。
  • iText PDF ライブラリー: この iText ライブラリーを使用して、PDF 文書を簡単に作成、操作することができます。
  • Spring: Spring の最新リリースをダウンロードしてください。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology, Open source
ArticleID=368155
ArticleTitle=Groovy 流の Spring: 第 1 回 統合の基本
publish-date=01062009