まず本題に入る前に、ApacheCamelの簡単な説明から
Apache Camelとは
Javaのフレームワーク。どんなフレームワークかというと
- ベルトコンベア(ライン生産的な)フレームワーク
- 「生産物」に相当するものはデータ
- 「生産物を作るロボットや人」に相当するものはコンポーネントや個別実装
- 「スタート」は外部からのリクエストやタイマーでの監視(例えばメールチェックみたいな)
- 「最終生成物」はリクエストもらった人に返す
- フレームワーク自体は超軽量。
概要すぎるので、もうちょっと細かな話をすると
データ
-
エクスチェンジ
と呼ばれる「箱」でベルトコンベアに流れている - 箱の中には
メッセージ
と呼ばれる生産物が入っている - 箱の中には
メッセージ
の他に「エラー」やIDや処理過程の「パンくずリスト」なども入っている -
メッセージ
の中はヘッダー
とボディ
があって、ヘッダー
がMap型、ボディ
がObject型になっている。メインとなるデータはボディ
で作って、サブ的なデータはヘッダー
にどんどん入れていく使い方。 - 例えばファイルでいうと、ファイルの中身が
ボディ
、ファイ名やサイズ、日付等がヘッダー
といった感じ。 - Camelではベルトコンベアの事を
ルート
と呼んでいる
コンポーネントや個別実装
<動作内容>
- ベルトコンベアから箱をもらうので、中身を取り出す
- 内容を見て処理をする
- 処理した結果を箱に入れる
-
コンポーネント
は色々準備されていて、外部システム接続の部分だったり、データ変換だったりが100種類以上用意されている。 -
コンポーネント
は独自な実装というよりも、外部のよく使われているOSSライブラリのラッパーになっている - 既存のコンポーネントに頼らずとも、もちろん独自に自分で実装もできる。
外部からのリクエストやタイマー
- HTTPリクエストなどを受信
- その他のプログラムからのリクエストを受け取る
- タイマーは1秒間隔だったり、毎週月曜だったり
- ファイルコンポーネントをスタートに配置すると、毎秒指定のディレクトリをチェックして、新規ファイルがあったら読み込むといった処理になる
もっと細かな説明やサンプルは別の機会に書くことにして、理由のほうを。
理由1 > 既存コンポーネントが便利
- ファイルを出力するコンポーネントを
ルート
に配置して、ヘッダー
にファイル名、ボディ
に内容を入れて渡すとファイルを生成してくれるといった感じ。 - メールコンポーネントはメールを送ってくれる
- Execコンポーネントはシェルやバッチファイルを起動してくれ、結果を
ボディ
につめてルート
に戻してくれる - コンポーネントを使うと個別のライブラリの使用方法をいちいち勉強しなくてもすむ
- コンポーネントは全部で http://camel.apache.org/components.html と http://camel.apache.org/data-format.html の2ページ。
- コンポーネントもシンプルな作りなので、機能が足りなかったりしても自分でextendして機能を継ぎ足せる。
理由2 > どこでも動く
- JavaVMのみでも
- Tomcatでも
- GoogleAppEnginでも
- JBossでも
- Groovyでも
- JUnitでも
- Jenkinsでも
軽量ライブラリだから環境選ばない。
軽量ライブラリだから、コンポーネントだけを使うという方法もできるんだけど、それは別の機会に説明。
理由3 > コードが読みやすくなる
- コードの大きな流れを読むには
ルート
(ベルトコンベア)を見ればいいだけ - やりたい事を順に
ルート
に並べていく - 細かな処理は
ルート
から呼び出す処理に書ける - いろんな所に変数が散らばらない。すべての情報は
エクスチェンジ
に入れるだけ。 - 設計もいたって簡単になって、メインはデータ部分とベルトコンベアでの機能分割になると思う。
- クラス変換が便利。クラスキャストのノリでクラス変換(データマッピング)ができる。
理由4 > デバッグがしやすい
-
エクスチェンジ
という箱の中身を見ると全部の処理中のデータが詰まっている。 - つまり
エクスチェンジ
をログ出力すると、処理中のデータがすべて見える。 - エラーが発生するとスタックトレースとパンくずリスト(ベルトコンベア上でどの処理を通ったか)やエクスチェンジの内容全部がログに出力される
- 試験コードが書きやすい。できていない処理を飛ばしてデータを流す事もできる。どう書けばいいかは、また別の機会。
理由5 > 複数人数で開発・分業しやすい
- ベルトコンベア式だから、これができないとだねぇ。
- どの処理でも
エクスチェンジ
という同じ箱を使うので、前の処理が完成していなくても実装可能。 - 処理単体での試験もできる。(想定データをエクスチェンジに詰めて投げるだけ)
理由6 > 意外としっかりした作り
- 軽量なフレームワークなので、逆に機能不足かと思いきや・・・
- EIPとか呼ばれる(https://www.graffletopia.com/stencils/137) 処理フローパターンを網羅するように意識して実装されている
- 例外ハンドラ、トランザクション制御、リトライ制御、グレースフルな停止(処理中のデータが処理完了するまで待つ)、処理回数や時間などの統計などなど。
- エラーになった処理(例えば外部にhttpリクエスト)を飛ばして後続の処理に進むという強制続行的なハンドリングすることもできる。
理由7 > ネタ的に
- ルートはワンライナーで書けちゃう。
サンプル
HelloWorldなサンプルぐらい1個つけておかないと実感もできないのでちょっとだけ。
ルート
(ベルトコンベア部分)は下記のようになる。
from("jetty:http://0.0.0.0:8081/api")
.to("sql:SELECT * FROM students WHERE id = :#id")
.marshal().json(JsonLibrary.Gson)
.to("log:resultMessage");
これを起動するとwebサーバ的な動作するので、次のようにアクセスすると
http://localhost:8081/api?id=1234
sqlが実行されて、結果のレコードがjson形式で結果として戻ってくる。
ログには結果データが吐出される。
といった感じ。
すべて既存コンポーネントをつなげただけで完成したので、独自実装が入ってない。
SQLの設定部分が書いてないのでこのままだと動かないけど、全体は次回にでも。