← Spring コース
50. 自動構成は候補を条件でふるいにかける
は、候補の一覧を条件でふるいにかける仕組みです。自動構成を提供する の spring に、名前が で終わるファイルがあり、構成の名前が1行ずつ並んでいます。 だけの場合は 39 個中6つの JAR に合計 30 行でした。 は起動時にこれを読み、各クラスの条件を評価して、通った だけを登録します。
条件は主に2種類です。 は指定のクラスがにあるか、 は同じ型の Bean が無いかを見ます。後者が付いた jacksonJsonMapper は、自分で同じ型の Bean を定義すると登録されなくなりました。は目印で、意味を与えるのは読む側の Boot という構図は第1セクションのアノテーションとの回と同じです。
何が通ったかは、 を付けて起動するとに出ます。この最小アプリでは通ったものが 52 件、通らなかったものが 39 件でした。件数は条件が評価されたクラスや Bean の見出しの数で、imports の 30 行とは数える対象が違います。また 4.1.1 の imports は JAR ごとに分かれ、spring-boot-autoconfigure にあるのは 12 行だけです。
点線の付いた語はタップすると説明が出ます。用語集を開く →
クラスパス上の JARこのうち6つが imports ファイルを持っていた
各 JAR の AutoConfiguration.imports を読む
候補の一覧(合計 30 行)構成クラスの名前が1行に1つ
依存を足すと候補そのものが増える候補ごとに条件を評価する
@ConditionalOnClassこのクラスがクラスパスにあるか
@ConditionalOnMissingBean同じ型の Bean がまだ無いか
結果で分かれる
通ったBean が登録される(例: jacksonJsonMapper)
通らなかった何も登録されない(例: CBOR 用の構成。CBORMapper が無い)
- ・条件のアノテーションはほかにもあります。リファレンスは、自動構成クラスはふつうこの2つを使うと書いています
- ・@ConditionalOnClass には、実行時のクラスパスに無いかもしれないクラスをそのまま書けます。クラスを読み込む前に、.class のバイト列からアノテーションの情報を読むためです。Boot の Javadoc はこれを ASM というライブラリで解析すると書いていますが、Spring Framework の公式ブログによると、7.0 は Java 24 以降では JDK の Class-File API で読みます
- ・通らなかった候補はエラーにならず、静かに外れます。理由は --debug の条件評価レポートの Negative matches に出ます
サンプルコード(フレームワーク環境が必要なため表示のみ)
// (1) Boot 側: JacksonAutoConfiguration.java の抜粋
// 出所: spring-boot-jackson 4.1.1 / org.springframework.boot.jackson.autoconfigure
// (右の日本語コメントは教材で付けたもの。import は省略)
@AutoConfiguration
@ConditionalOnClass(JsonMapper.class) // JsonMapper がクラスパスにあるときだけ、この構成クラスを使う
public final class JacksonAutoConfiguration {
// ...
@Bean
@Primary
@ConditionalOnMissingBean // JsonMapper 型の Bean がまだ無いときだけ登録する
JsonMapper jacksonJsonMapper(JsonMapper.Builder builder) {
return builder.build();
}
// ...
}
// (2) 自分の側: CustomApp.java — 同じ型の Bean を自分で定義する
package l17.custom;
@SpringBootApplication
public class CustomApp {
@Bean
JsonMapper myJsonMapper() { // define the bean ourselves
return JsonMapper.builder().build();
}
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(CustomApp.class, args);
System.out.println("JsonMapper beans = " + java.util.List.of(ctx.getBeanNamesForType(JsonMapper.class)));
ctx.close();
}
}
// 出力(起動ログを除く)
// myJsonMapper を定義する前: JsonMapper beans = [jacksonJsonMapper]
// myJsonMapper を定義した後: JsonMapper beans = [myJsonMapper]
図やコードに出てくる用語(タップで説明)
サンプルコードで身につける(5本) →
学んだ概念を、素朴な例から実務寄りの例まで5つの具体例で確認します。
公式ドキュメントで詳しく ↗