Spring Bootでstarterを作る際のベストプラクティスを考える

Spring

Spring Bootから導入されたstarterプロジェクトという考え方ですが、依存ライブラリの一元管理や共通部品実装というかフレームワークの提供などを目的に独自にstarterプロジェクトを作ることもままあることかと思います。この間お仕事でもちょこっと作ったのですがなんとなく考えたことなどを少々まとめます。

スポンサーリンク

前提バージョン

この記事で使用した各種ライブラリのバージョンは以下の通り。

  • Spring Boot:2.1.2.RELEASE
  • Gradle:5.1.1

starterとは

Spring Bootを使用して開発をしたことがある人であればわかると思いますが、簡単に言えば依存関係を設定するだけで依存ライブラリの引き込みとauto-configurationが有効になるライブラリのこと。

Spring Bootのプロダクトとして様々なstarterが用意されています。

spring-projects/spring-boot
Spring Boot. Contribute to spring-projects/spring-boot development by creating an account on GitHub.

starterの作り方

独自starterの作り方はリファレンスに説明があります。

48. Creating Your Own Auto-configuration

手順をピックアップすると

  • auto-configurationモジュールを作成する
    • @Configurationを付与したクラスを用意
    • META-INF/spring.factoriesEnableAutoConfigurationを設定
  • auto-configurationモジュールと必要なライブラリへの依存関係を設定したstarterモジュールを作成

まぁこれだけなのですが。auto-configurationあるいは依存関係に含めたい独自実装があれば含めておけばよいわけです。

注意したポイント

私の場合は共通部品実装を提供する目的でstarterプロジェクトを作成したのですが、ライブラリの依存関係をどのように伝搬させるか、それに伴ってモジュール構成をどうすべきか、というところに少し悩みました。

依存関係の伝搬パターン

これはstarterを利用させる目的にも依るのですが、大きく2つパターンがあるかなと思います。

依存ライブラリを統一する

ガバナンスを効かせる目的で複数のアプリケーションで共通的に使用するライブラリをstarterプロジェクトにまとめて定義してしまい、starter経由で依存関係を設定することでバージョンを合わせる、というパターン。

利用者側アプリケーションの開発者があまり細かいことを気にせずにロジックだけを書いている方が効率がいい場合などはこのパターンが良い気がします。

独自フレームワークのみを伝搬させる

auto-configurationモジュールおよび独自実装への依存関係のみを伝搬させ、Spring Bootのバージョンを含め、前提とするライブラリは使う側に選択の余地を残すパターン。auto-configurationモジュールおよび独自実装では依存するライブラリをimplementationで定義し、starterモジュールではapiでauto-configurationモジュールおよび独自実装だけを伝搬させる感じです。

もちろんどのバージョンでも動くということではないと思うので、対応しているバージョンでのバリエーションテストを実行してこのバージョンのライブラリならOK、というのをある程度出しておくか、利用するアプリケーション側のテストでカバーするかが必要になるパターンかと思います。

このパターンは利用するアプリケーション側である程度裁量が必要な場合に向いているかと。

モジュール構成

依存関係の伝搬パターンを踏まえて、プロジェクト構成を考えてみます。

auto-configuration + starter

前述のリファレンスに記載のパターン。

auto-configurationモジュールに実装 + META-INF/spring.factoriesの設定を含め、starterモジュールには依存関係の定義のみを行います。

Spring Boot本体の実装は、複数のstarterが利用するauto-configurationを集約しています。

spring-projects/spring-boot
Spring Boot. Contribute to spring-projects/spring-boot development by creating an account on GitHub.

その上で、@ConditionalOnClassなどを使って必要な場合のみBean定義が有効になるようになっています。

1モジュール

規模が小さい場合など、1モジュールにauto-configurationと依存関係設定を集約してしまっても良い(と、リファレンスにも書いてあります)。挙動としては同じなので、見通しの良さを優先して集約しても良いということですね。

starterにspring.factoriesがいても良いんじゃないか

リファレンスに説明されているパターンはこんな感じなのですが、おまけで前者のパターンでstarterの方にMETA-INF/spring.factoriesがいても良いんじゃないかなぁと思ったりしています。

starterがごちゃごちゃしているのはもちろん良くないと思いますが、starterモジュールの役割は依存関係の設定とauto-configurationの有効化だと思うので、この2点をstarterモジュールの中身をみてわかった方がやりやすいんじゃないかと。

複数のstarterを作る場合にEnableAutoConfigurationの設定が色んな所にあると混ざって危険(カチあったらもちろんダメなので)ということもあるかもしれませんが、starter作るような人って限られた人だと思うのでその辺はなんとかなるんじゃないかなぁと思います。もちろん現場によると思いますが。

まとめ

Spring Bootでstarterを作るときに依存関係の伝搬とモジュール構成をちょっと考えました、というお話でした。結局どうしたのかというと、私の今やっている仕事では

  • auto-configurationモジュールおよび独自実装のみを伝搬
  • starterとauto-configurationモジュールは分けて、spring.factoriesはstarterに配置

starterは当分私しかいじらないし、使う側はのびのび生まれてくる感じがしたのでこんな感じにしました。はてさて。

といいつつ迷ったら基本的にSpring Boot本家と同じ雰囲気で作っておけば外さないと思うので、そこは現場の事情とかを鑑みて、というところでしょうか。

この記事コードが全然ないですね(゚Д゚)

Springの新しい本が出るらしい

この記事に対するコメント