【Spring Initializr 読解】initializr-web: InitializrAutoConfiguration.java 編

[【Spring Initializr 読解】initializr-web: ProjectMetadataController.java 編](https://qiita.com/nimzo6689/items/1e15f124addf33f14f8d) の続編です。

この記事では、引き続き initializr のサブモジュール `initializr-web` について、特に Auto Configuration の実装を追っていきます。

https://github.com/spring-io/initializr/blob/ad03a71a30b89457fb97dff11dcb103565735fba/initializr-web/src/main/java/io/spring/initializr/web/autoconfigure/InitializrAutoConfiguration.java

# InitializrAutoConfiguration の概要

Spring Initializr の自動設定（Bean を DI コンテナに登録）を行うクラスです。Web 環境では、 Controller をアプリケーション全体で利用可能にするため、それらを DI コンテナに登録しています。

```java
@AutoConfiguration(after = { JacksonAutoConfiguration.class, RestTemplateAutoConfiguration.class })
@EnableConfigurationProperties(InitializrProperties.class)
public class InitializrAutoConfiguration {
    // 実装内容
}
```

この自動設定クラスは、Jackson と RestTemplate の自動設定の後に実行されるように設定されています。
また、 InitializrProperties にて、`application.yaml` や `application.properties` に定義された `initializr` から始まる設定値を先にバインドさせています。

# 主要な Bean 定義

全体的に、 `@ConditionalOnMissingBean` が多用されているため、必要に応じて各コンポーネントをカスタマイズ可能にさせる設計となっています。

## プロジェクト生成関連

```java
@Bean
@ConditionalOnMissingBean
public ProjectDirectoryFactory projectDirectoryFactory() {
    return (description) -> Files.createTempDirectory("project-");
}
```

プロジェクトの一時ディレクトリを生成するためのファクトリです。"project-" プレフィックス付きの一時ディレクトリを作成します。

```java
@Bean
@ConditionalOnMissingBean
public IndentingWriterFactory indentingWriterFactory() {
    return IndentingWriterFactory.create(new SimpleIndentStrategy("\t"),
            (builder) -> builder.indentingStrategy("yaml", new SimpleIndentStrategy("  ")));
}
```

ファイル生成時のインデント設定を行うファクトリです。

- 通常のファイル: タブ文字でインデント
- YAML ファイル: スペース 2 個でインデント

## テンプレート関連

```java
@Bean
@ConditionalOnMissingBean(TemplateRenderer.class)
public MustacheTemplateRenderer templateRenderer(Environment environment,
        ObjectProvider<CacheManager> cacheManager) {
    return new MustacheTemplateRenderer("classpath:/templates",
            determineCache(environment, cacheManager.getIfAvailable()));
}
```

Mustache テンプレートエンジンの設定です。`classpath:/templates` 配下のテンプレートファイルを使用します。また、環境設定に応じてテンプレートのキャッシュを有効化します。

## メタデータ関連

```java
@Bean
@ConditionalOnMissingBean(InitializrMetadataProvider.class)
public InitializrMetadataProvider initializrMetadataProvider(InitializrProperties properties,
        ObjectProvider<InitializrMetadataUpdateStrategy> initializrMetadataUpdateStrategy) {
    InitializrMetadata metadata = InitializrMetadataBuilder.fromInitializrProperties(properties).build();
    return new DefaultInitializrMetadataProvider(metadata,
            initializrMetadataUpdateStrategy.getIfAvailable(() -> (current) -> current));
}
```

Spring Initializr のメタデータ（依存関係、バージョン、パッケージングなど）を提供するプロバイダーを設定します。
ここで生成された `InitializrMetadataProvider` は後ほど紹介する各 Controller のコンストラクタの引数として参照されています。前回の記事でルートパスにリクエストすると、JSON で依存関係などの情報が取得できましたが、その取得元もこちらの Spring Bean になります。

# Web 関連の設定クラス

`@Configuration` のネストクラスとして Web 関連の設定が定義されています。
また、 `@ConditionalOnWebApplication` により Web アプリとして起動されたときのみ適用させています。具体的には、`spring-boot-starter-web` を依存関係に追加し、 `@SpringBootApplication` を追加してその main メソッドから実行などすれば有効にできます。

```java
@Configuration
@ConditionalOnWebApplication
static class InitializrWebConfiguration {
    // Web関連のBean定義
}
```

定義されている Controller はこちらです。

1. `ProjectGenerationController`: プロジェクト生成を担当
2. `ProjectMetadataController`: メタデータ提供を担当
3. `CommandLineMetadataController`: CLI メタデータ提供を担当
4. `SpringCliDistributionController`: Spring CLI 配布を担当

# キャッシュ設定

```java
@Configuration
@ConditionalOnClass(javax.cache.CacheManager.class)
static class InitializrCacheConfiguration {
    @Bean
    JCacheManagerCustomizer initializrCacheManagerCustomizer() {
        return new InitializrJCacheManagerCustomizer();
    }
}
```

JCache (JSR-107) を使用したキャッシュ設定です。以下の 4 つのキャッシュが定義されています：

1. `initializr.metadata`: メタデータ（10 分で期限切れ）
2. `initializr.dependency-metadata`: 依存関係メタデータ
3. `initializr.project-resources`: プロジェクトリソース
4. `initializr.templates`: テンプレート

# imports ファイル

自動的にロードする設定クラスとして以下のファイルに InitializrAutoConfiguration を定義しています。

```java:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
io.spring.initializr.web.autoconfigure.InitializrAutoConfiguration
```

これにより、違う SpringBoot のプロジェクトから参照された際に、そちらの SpringBoot にこの設定ファイルがロードされるように指示が出せます。

# 参考

https://spring.pleiades.io/spring-boot/reference/features/developing-auto-configuration.html