tokuhirom's Blog

Amon2のアーキテクチャとトリガ機構 〜 軽量フレームワークAmon2入門 (2) 〜

さて、今回は Amon2 のアーキテクチャについてです。

Amon2のアーキテクチャ

まずはこちらの図をごらんください。

Amon2 の構造は非常に単純であることをご理解いただけたかとおもいます。基本的な構造はこれがすべてなのです。なにしろ、できるだけおぼえることがすくなくなるように意図して設計されておりますから、こういうシンプルな構造になるのもあたりまえといえましょう。

ここで特徴的なところが二点あります。Web Context Object が Context Object を継承しているところ、レスポンスオブジェクトが has-a 関係ではないところです。

Web Context Object が Context Object を継承しているのは、CLI でもなんとなくつかえるようにするためです。この工夫により CLI での開発が異常に楽になっています。このあたりについてはおって解説したいとおもっています。

レスポンスオブジェクトが has-a 関係ではないのはちょっとめずらしいかもしれません。Catalyst は Response Object のインスタンスを $c がもっていますね。しかし Amon2 では、$c->create_respose() メソッドでレスポンスオブジェクトのインスタンスを生成するだけです。むしろこのメソッド自体はよばなくてもかまいません。Plack::Response->new() を直接よんでもいいのです。これは、得に has-a 関係をもたせる意味をかんじないからそうしているだけというか、逆に Catalyst のような形式にするメリットが僕にはかんじられないのです。

Amon2 では $c->dispatch() というメソッドによってリクエストが実際に処理されますが、このメソッドのシグネチャが以下のようになっています。

my $c = MyApp::Web->new(env => $env);
my $response = $c->dispatch();

つまり、コントローラはレスポンスオブジェクトを返り値としてかえすということです。この形式は非常にわかりやすいものだとおもっています。

Amon2 とトリガー

Amon2 ではトリガーというフック機構をとりいれています。これは Sledge というフレームワークの影響をうけた機能です。

トリガーのフックポイントは3個所用意されています。

  • BEFORE_DISPATCH
  • AFTER_DISPATCH
  • HTML_FILTER

の3種類です。

BEFORE_DISPATCH は、ディスパッチャがよばれる前のタイミングでよばれます。

__PACKAGE__->add_trigger(BEFORE_DISPATCH => sub { my $c = shift; ... });

このフックの返り値が Plack::Response のインスタンスであった場合、そのレスポンスオブジェクトをそれをレスポンスとして処理します。

AFTER_DISPATCH はディスパッチャがよばれた後のタイミングでよばれます。$response はディスパッチャで生成されたレスポンスオブジェクトです。このタイミングでレスポンスにたいするフィルタ処理などをおこなうことができます。

__PACKAGE__->add_trigger(AFTER_DISPATCH => sub { my ($c, $response) = @_; ... });

AFTER_DISPATCH は $c にたいしてそのリクエストの中でだけかけることもできます。たとえば以下のようにすることができます。

sub index {
  my $c = shift;
  $c->add_trigger(AFTER_DISPATCH => sub { ... });
  ...
}

HTML_FILTER は HTML にたいするフィルタ処理をおこないます。View オブジェクトをつかって HTML を生成したタイミングでよばれます。$html は utf-8 flag がついた状態の文字列です。このフックでは返り値はフィルタ処理済の HTML 文字列にする必要があります。

__PACKAGE__->add_trigger(HTML_FILTER => sub { my ($c, $html) = @_; ... });

まとめ

今回は Amon2 のアーキテクチャとトリガ構造について解説しました。Amon2 はシンプルなコアと無限の拡張性を意図して開発されているということがわかったかとおもいます。

次回はいよいよチュートリアルにはいっていきます(たぶん)。