Micronautの@Factoryとは?複雑なBean生成を管理するための方法を解説
生徒
「Micronautで@Factoryというアノテーションを見かけたんですが、これは何をするものなんですか?」
先生
「@Factoryは、少し複雑なBeanの生成処理をまとめて管理するための仕組みです」
生徒
「@Singletonや@Prototypeと何が違うんですか?」
先生
「それらはクラスそのものをBeanにしますが、@FactoryはBeanを作るためのクラスです」
生徒
「どういう場面で使うのか知りたいです」
先生
「では、DIの基本を振り返りながら、@Factoryの役割を見ていきましょう」
1. MicronautのDIとBean生成の基本
Micronautでは、DIによってオブジェクトの生成と管理をフレームワークが担当します。 開発者は、どのクラスをBeanとして使うかをアノテーションで指定するだけです。 これにより、newを直接書かずに、安全でテストしやすいコードが書けるようになります。
多くの場合は、@Singletonや@Prototypeをクラスに付けるだけで十分です。 しかし、生成時に条件分岐が必要だったり、外部設定を使った初期化が必要な場合もあります。 そのようなときに活躍するのが@Factoryです。
2. @Factoryとは何か
@Factoryは、Beanを生成するためのクラスを定義するアノテーションです。 @Factoryが付いたクラスの中で、Beanを返すメソッドを定義することで、 Micronautはその戻り値をDIコンテナに登録します。
つまり、@Factoryは「Beanそのもの」ではなく、 「Beanを作る責任を持ったクラス」と考えると分かりやすいです。 複雑な初期化処理を一か所にまとめられる点が大きな特徴です。
3. @Factoryの基本的な書き方
@Factoryはクラスに付与し、その中でBeanを返すメソッドを定義します。 メソッドには@Singletonや@Prototypeなどのスコープを指定します。
import io.micronaut.context.annotation.Factory;
import jakarta.inject.Singleton;
@Factory
public class ServiceFactory {
@Singleton
public SampleService sampleService() {
return new SampleService("default");
}
}
public class SampleService {
private final String name;
public SampleService(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
この例では、SampleServiceは直接Beanとして定義されていません。 代わりに、Factoryクラスのメソッドを通して生成されます。 これにより、生成ロジックを柔軟に制御できます。
4. なぜ@Factoryが必要なのか
単純なクラスであれば、クラスに@Singletonを付けるだけで問題ありません。 しかし、生成時に設定値を組み合わせたり、 複数の条件によって生成方法を変えたい場合には、クラスに直接書くと複雑になります。
@Factoryを使えば、生成ロジックを専用クラスに切り出せます。 これにより、責務が分離され、コードの見通しが良くなります。 初心者でも、役割を意識しながら設計しやすくなる点がメリットです。
5. 複数のBeanを生成するFactory
一つの@Factoryクラスの中で、複数のBeanを定義することも可能です。 関連するBeanをまとめて管理できるため、構成が分かりやすくなります。
import io.micronaut.context.annotation.Factory;
import jakarta.inject.Singleton;
@Factory
public class ConfigFactory {
@Singleton
public ConfigService configService() {
return new ConfigService("prod");
}
@Singleton
public HelperService helperService() {
return new HelperService();
}
}
このように、設定や補助的なサービスをまとめて生成することで、 アプリケーション全体の構成が整理されます。
6. @Factoryとスコープの関係
@Factory自体にはスコープの意味はありません。 実際のスコープは、Beanを返すメソッドに付与されたアノテーションで決まります。
@Singletonを付ければ一つのインスタンスが共有され、 @Prototypeを付ければ呼び出されるたびに新しいインスタンスが生成されます。 この組み合わせにより、柔軟な設計が可能になります。
7. @Factoryを使う際の注意点
@Factoryは強力ですが、使いすぎると構成が分かりにくくなる場合があります。 単純なクラスまでFactoryで管理すると、かえって理解しづらくなることもあります。
まずは、複雑な生成処理が必要な場合に限定して使うのがおすすめです。 初心者のうちは、@Singletonと@Prototypeを基本にして、 必要になったタイミングで@Factoryを導入するとスムーズに理解できます。
まとめ
MicronautにおけるFactoryは、複雑なBean生成を整理し、アプリケーション全体の設計をより明確にするための重要な仕組みです。通常のDIでは、クラスにSingletonやPrototypeといったスコープを付与することで簡単にBeanを管理できますが、実務の開発ではそれだけでは対応しきれない場面が多く存在します。例えば、外部設定ファイルの値を読み込んで初期化したい場合や、環境によって生成するインスタンスを切り替えたい場合、あるいは複数の依存関係を組み合わせて一つのオブジェクトを構築する必要がある場合などです。こうしたケースにおいてFactoryを活用することで、生成ロジックを一箇所に集約でき、可読性と保守性を大きく向上させることができます。
また、Factoryを導入することで責務の分離が明確になります。クラス自身はビジネスロジックに専念し、生成に関する責任はFactoryに任せるという構造にすることで、コードの見通しが良くなります。これは大規模開発において特に重要なポイントであり、将来的な拡張やリファクタリングにも強い設計につながります。さらに、テストの観点でもFactoryは有効で、生成処理を差し替えることでモックの注入などが柔軟に行えるようになります。
一方で、Factoryは便利な反面、過度に使用すると逆に複雑さを招く可能性もあります。単純なクラスまでFactoryで管理してしまうと、どこでインスタンスが生成されているのか分かりにくくなり、学習コストも上がってしまいます。そのため、基本はSingletonやPrototypeを使い、どうしても生成処理が複雑になる場合にのみFactoryを採用するというバランスが重要です。初心者の方は、まずDIの基本をしっかり理解した上で、必要に応じてFactoryを導入する流れを意識すると良いでしょう。
サンプルプログラムで理解を深める
次のサンプルでは、設定値によって異なるサービスを生成するFactoryの例を示します。環境に応じてインスタンスを切り替えることで、柔軟な構成が実現できます。
import io.micronaut.context.annotation.Factory;
import jakarta.inject.Singleton;
@Factory
public class EnvironmentFactory {
@Singleton
public MessageService messageService() {
String env = System.getProperty("env", "dev");
if ("prod".equals(env)) {
return new MessageService("本番環境");
} else {
return new MessageService("開発環境");
}
}
}
public class MessageService {
private final String message;
public MessageService(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
このようにFactoryを利用することで、条件分岐を含む生成ロジックを簡潔に記述でき、アプリケーション全体の構造が整理されます。特に設定値や環境変数と組み合わせることで、実務に即した柔軟な設計が可能になります。
生徒
Factoryを使う理由がだいぶ分かってきました。単純なクラスには不要だけど、複雑な生成処理にはとても便利なんですね。
先生
その通りです。特に設定値や条件分岐が絡むときに力を発揮します。生成処理を分離することで、コード全体が整理されます。
生徒
クラスに直接Singletonを付けるのと比べて、設計の自由度が上がる感じがしました。
先生
良い視点ですね。Factoryは柔軟性を高めるための仕組みです。ただし使いすぎには注意しましょう。
生徒
まずは基本のDIをしっかり理解して、必要な場面で使うようにします。
先生
それが一番良い進め方です。段階的に学ぶことで、実務でもしっかり活かせるようになります。