- 澁川喜規
- Programming
- 約 1,600 文字
- 2,300 View
アプリケーション開発のチームと、共有ライブラリチームに分かれているが、共有ライブラリ側でアプリ側にHTTPのエンドポイントを追加したい場合があると思います。例えば、特別なヘルスチェックのエンドポイントを足したいとか。
SpringBootのデモアプリとして作成したもの(Spring Starter ProjectでSpring Webだけ足したもの)をベースにやり方をまとめていきます。
SpringBootのコンポーネントスキャンの仕組み
SpringBootは、アプリケーションの骨格となるクラス(@SpringBootApplicationアノテーションがついている)と同じパッケージかその配下にあるクラスであれば、@RestControllerをつければ即座にHTTPのエンドポイントになってくれます。
こういうパッケージ構成だったとします。
├─jp.co.future.app // アプリケーション |
自動で作られるアプリケーションのクラスはこんな感じですね。
package jp.co.future.app; |
この場合、以下のように同一パッケージ配下に置いたクラスは自動で登録されます。
package jp.co.future.app; |
次のような、アプリケーションとは別のパッケージ配下のクラスで作ったヘルスチェック用のエンドポイントはそのままでは登録されないので、/healthにアクセスするとエラー画面が出ます。
package jp.co.future.app; |
SpringBootはデフォルトではアプリケーションと同一のパッケージかその下しかコンポーネントを探しに行かないので、スキャン先を教えてあげます。登録は@ComponentScanアノテーションを使うか、@SpringBootApplicationにパラメータを渡すか、どちらかの方法でできます。
import org.springframework.context.annotation.ComponentScan; |
|
これで使えるようになります、というところまでは調べれば出てくることではありますが、別の方式も試してみました。
コンポーネントスキャンを設定しないで、共有ライブラリを利用する
コンポーネントスキャンを設定しないでHTTPのエンドポイントに登録してもらうには、@RestControllerアノテーションだけはアプリ側において、ライブラリは中の実装だけに集中するという2段階に分ける方法が使えます。
├─jp.co.future.app // アプリケーション |
共有ライブラリの方は、先ほどの実装から@RestControllerを抜くだけです。
package jp.co.future.common; |
アプリ側の方は中身が空の@RestControllerだけがついているクラスを置いてあげればOKです。
package jp.co.future.app; |
これでいけます。
この方式を使うメリットは、どこのURLでこの機能を提供するかをアプリ側で変更したりもしやすかったりします。今回のヘルスチェックの例だとメリットは感じにくいですが、ログ出力とか認証チェックとか前後の共通処理を行うコントローラを1つ作って、アプリケーション側は中のロジックだけに集中するようにしてあげるとか、そういう用途とかも考えられますね。
まとめ
SpringBootのコンポーネントスキャン周りの仕組みを学びつつ、それを使わない方式とかも手元で試してみて動いたのでメモがてら書いてみました。前半の内容だけならググると出てくるのですが、後半の内容は見つからなかったのでブログにしてみました。
コンポーネントスキャンとかのこの手の「設定してね」は、個人的に、直感的でない作業感があるし、見落としがちだし、見落とした場合のデバッグが面倒というのもあり、そこまで好きではないです。宣言的なAPIとかはもてはやされたりもしますが、その宣言忘れの場合に何かチェックしてくれたり警告を出してくれるようなものがあれば良いのですが、だいたい存在しなかったりしますよね。@RequestMapping("/エンドポイント")はまだ、ブラウザにアクセスするときのURLがキーとなっているので、設定間違いを確認しやすいのでいいなと思うのですが、コンポーネントスキャンとかそういうのはなかなかたどり着くのが難しい。
宣言的APIはコードの短さゆえにいろいろなところで使われていますが、個人的にはバランスをとって使いたいなと思っているところです。