はじめに (対象読者・この記事でわかること)

この記事は、Spring Bootで開発しているが共通処理をライブラリ化したい方、マルチモジュールプロジェクトの構築に興味がある方向けです。Spring Bootアプリケーションをライブラリとして切り出し、複数のプロジェクトで再利用する方法について解説します。この記事を読むことで、Spring Bootアプリをライブラリ化する具体的な手順、マルチモジュール構成のメリット、Gradleでの設定方法がわかります。また、実際に動作するサンプルコードも提供するので、すぐに実践できるようになります。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 - Javaの基本的な知識(クラス、インターフェース、パッケージ) - Spring Bootの基礎(アノテーション、DI、AutoConfiguration) - Gradleでのビルド設定の基礎

なぜSpring Bootアプリをライブラリ化するのか?

Spring Bootアプリケーションを開発していると、「この処理、別のプロジェクトでも使いたいな」と思うことはありませんか?認証処理、ロギング、カスタムアノテーション、共通のユーティリティクラスなど、プロジェクトをまたいで使いたい処理は意外と多くあります。

従来の方法だと、コードをコピー&ペーストしたり、jarファイルを手動でコピーしていたりすると思います。しかし、これではバージョン管理が大変で、バグ修正や機能追加が面倒です。

そこで登場するのがSpring Bootアプリケーションのライブラリ化です。Spring BootのAutoConfiguration機能を活用することで、ライブラリとして利用する側は「依存関係を追加するだけ」で、簡単に機能を利用できるようになります。

主なメリットは以下の通りです:

  • 再利用性の向上:一度実装した機能を複数プロジェクトで共有
  • 保守性の向上:ライブラリを修正するだけで、すべてのプロジェクトが更新
  • 開発効率の向上:共通処理に時間をかけずに、ビジネスロジックに集中できる
  • テスタビリティ:ライブラリ単体でテストを実行可能

Spring Bootライブラリの作り方〜マルチモジュール構成で実装する〜

それでは、実際にSpring Bootアプリケーションをライブラリ化する方法を見ていきましょう。ここでは、認証処理を担当するライブラリを作成する例で説明します。

プロジェクト構成の設計

まず、マルチモジュールプロジェクトの構成を設計します。今回は以下のような構成にします:

spring-boot-library-example/
├── authentication-library/     # ライブラリモジュール
│   ├── src/main/java/
│   │   └── com/example/auth/
│   │       ├── config/
│   │       │   └── AuthAutoConfiguration.java
│   │       ├── service/
│   │       │   └── AuthenticationService.java
│   │       └── annotation/
│   │           └── EnableAuth.java
│   └── src/main/resources/
│       └── META-INF/
│           └── spring.factories
└── sample-application/        # ライブラリを使用するアプリケーション
    └── src/main/java/
        └── com/example/app/
            └── Application.java

ステップ1:ライブラリモジュールの作成

まず、ルートディレクトリでsettings.gradleを作成します:

Groovy
rootProject.name = 'spring-boot-library-example' include 'authentication-library' include 'sample-application'

次に、ライブラリモジュールのbuild.gradleを設定します:

Groovy
plugins { id 'java-library' id 'org.springframework.boot' version '3.2.0' id 'io.spring.dependency-management' version '1.1.4' } group = 'com.example' version = '1.0.0' java { sourceCompatibility = '17' } dependencyManagement { imports { mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES } } dependencies { implementation 'org.springframework.boot:spring-boot-starter' implementation 'org.springframework.boot:spring-boot-autoconfigure' annotationProcessor 'org.springframework.boot:spring-boot-autoconfigure-processor' annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' testImplementation 'org.springframework.boot:spring-boot-starter-test' } tasks.named('bootJar') { enabled = false } tasks.named('jar') { enabled = true archiveClassifier = '' }

bootJarを無効にしてjarを有効にしている点が重要です。これにより、実行可能なjarではなく、ライブラリとして利用できるjarが生成されます。

ステップ2:AutoConfigurationの実装

Spring Bootの自動設定機能を利用するため、AuthAutoConfigurationクラスを作成します:

Java
package com.example.auth.config; import com.example.auth.service.AuthenticationService; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @ConditionalOnClass(AuthenticationService.class) @EnableConfigurationProperties(AuthProperties.class) public class AuthAutoConfiguration { @Bean @ConditionalOnMissingBean public AuthenticationService authenticationService(AuthProperties properties) { return new AuthenticationService(properties); } } @ConfigurationProperties(prefix = "app.auth") class AuthProperties { private String secretKey = "default-secret"; private long tokenExpiration = 3600; // getters and setters public String getSecretKey() { return secretKey; } public void setSecretKey(String secretKey) { this.secretKey = secretKey; } public long getTokenExpiration() { return tokenExpiration; } public void setTokenExpiration(long tokenExpiration) { this.tokenExpiration = tokenExpiration; } }

@ConditionalOnMissingBeanアノテーションを使用することで、アプリケーション側で同じ型のBeanを定義している場合は、自動設定を上書きできます。

ステップ3:spring.factoriesの設定

Spring Boot 2.7以降はspring/org.springframework.boot.autoconfigure.AutoConfiguration.importsを使用しますが、互換性のためにここではspring.factoriesを使用します:

Properties
# src/main/resources/META-INF/spring.factories org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.auth.config.AuthAutoConfiguration

これにより、Spring Bootアプリケーションが起動時に自動的にAuthAutoConfigurationを読み込みます。

ステップ4:カスタムアノテーションの作成

ライブラリを使用する側が、明示的に認証機能を有効化できるように、カスタムアノテーションを作成します:

Java
package com.example.auth.annotation; import com.example.auth.config.AuthAutoConfiguration; import org.springframework.context.annotation.Import; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(AuthAutoConfiguration.class) public @interface EnableAuth { }

これにより、アプリケーション側で@EnableAuthを付けるだけで、認証機能が有効になります。

ステップ5:実装例 - 認証サービス

実際の認証処理を行うサービスクラスを実装します:

Java
package com.example.auth.service; import com.example.auth.config.AuthProperties; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.stereotype.Service; import java.util.Date; @Service public class AuthenticationService { private final AuthProperties properties; public AuthenticationService(AuthProperties properties) { this.properties = properties; } public String generateToken(String username) { Date now = new Date(); Date expiry = new Date(now.getTime() + properties.getTokenExpiration() * 1000); return Jwts.builder() .setSubject(username) .setIssuedAt(now) .setExpiration(expiry) .signWith(SignatureAlgorithm.HS512, properties.getSecretKey()) .compact(); } public boolean validateToken(String token) { try { Jwts.parser().setSigningKey(properties.getSecretKey()).parseClaimsJws(token); return true; } catch (Exception e) { return false; } } }

ステップ6:ライブラリの公開(ローカルリポジトリ)

開発中は、ローカルリポジトリに公開してテストすると便利です:

Groovy
// authentication-library/build.gradleに追加 publishing { publications { maven(MavenPublication) { from components.java } } }

そして、以下のコマンドで公開:

Bash
./gradlew publishToMavenLocal

ハマった点やエラー解決

問題1:AutoConfigurationが読み込まれない

症状:ライブラリを追加しても、Beanが作成されない

原因spring.factoriesの場所が正しくない、または内容に誤りがある

解決策src/main/resources/META-INF/spring.factoriesに正確に配置し、完全修飾クラス名を記載

問題2:Beanの競合が発生する

症状:アプリケーション側で同じ型のBeanを定義すると、エラーになる

原因@ConditionalOnMissingBeanを付け忘れている

解決策:AutoConfigurationクラスの@Beanメソッドに@ConditionalOnMissingBeanを付与

問題3:設定プロパティが読み込まれない

症状@ConfigurationPropertiesで定義したプロパティがデフォルト値のまま

原因@EnableConfigurationPropertiesを付け忘れている

解決策:AutoConfigurationクラスに@EnableConfigurationPropertiesを追加

ライブラリを使用する側の実装

最後に、作成したライブラリを実際に使用するサンプルアプリケーションを実装します:

Java
package com.example.app; import com.example.auth.annotation.EnableAuth; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableAuth // 認証ライブラリを有効化 public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

application.propertiesで設定をカスタマイズ:

Properties
# 認証ライブラリの設定 app.auth.secret-key=my-custom-secret-key app.auth.token-expiration=7200

そして、認証サービスを使用する例:

Java
package com.example.app.controller; import com.example.auth.service.AuthenticationService; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/auth") public class AuthController { private final AuthenticationService authService; public AuthController(AuthenticationService authService) { this.authService = authService; } @PostMapping("/login") public String login(@RequestParam String username) { return authService.generateToken(username); } @GetMapping("/validate") public boolean validate(@RequestParam String token) { return authService.validateToken(token); } }

まとめ

本記事では、Spring Bootアプリケーションをライブラリ化する方法について解説しました。マルチモジュール構成を採用することで、共通処理を効率的に管理・再利用できることがわかりました。

  • Spring BootのAutoConfiguration機能を活用することで、ライブラリの利用者は最小限の設定で機能を利用可能
  • @ConditionalOnMissingBeanなどの条件付きアノテーションを使用することで、柔軟な設定が可能
  • カスタムアノテーション(@EnableAuth)を作成することで、明示的な機能の有効化が可能
  • マルチモジュール構成により、ライブラリとアプリケーションを同一プロジェクト内で管理でき、開発効率が向上

この記事を通して、Spring Bootアプリケーションのライブラリ化が難しくないことが理解できたでしょう。ぜひ、プロジェクトで共通処理をライブラリ化して、開発効率を向上させてください。

今後は、Spring Boot 3.xでの新しい自動設定方法(spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports)や、Maven Centralへの公開方法についても記事にする予定です。

参考資料