Micronautの@Prototypeとは?新しいインスタンスを生成するスコープの基本
生徒
「Micronautで@Prototypeって書かれているクラスを見たんですが、@Singletonとは何が違うんですか?」
先生
「@Prototypeは、依存性注入されるたびに新しいインスタンスを生成するスコープです」
生徒
「毎回新しく作られるんですか?」
先生
「そうです。同じクラスでも、注入されるたびに別のオブジェクトになります」
生徒
「どういう場面で使い分けるのかが知りたいです」
先生
「では、@Prototypeの基本から順番に説明していきましょう」
1. Micronautにおけるスコープの基本
Micronautでは、DIによってオブジェクトの生成と管理をフレームワークに任せます。 その際に重要になるのがスコープという概念です。 スコープは、オブジェクトがいつ作られ、どの範囲で使われるかを決める仕組みです。
初心者が最初に触れるのは@Singletonですが、それとは対照的な存在が@Prototypeです。 この二つを理解すると、MicronautのDI設計が一気に分かりやすくなります。
2. @Prototypeとは何か
@Prototypeは、依存性注入されるたびに新しいインスタンスを生成するスコープです。 同じクラスであっても、使われる場所ごとに別々のオブジェクトが作られます。
そのため、状態を持つクラスや、一時的な処理を担当するクラスに向いています。 @Singletonのように使い回されることがないため、内部状態が他に影響する心配がありません。
3. @Prototypeの基本的な使い方
@Prototypeはクラスに付与するだけで利用できます。 特別な設定は不要で、Micronautが自動的に管理します。
import jakarta.inject.Prototype;
@Prototype
public class TaskProcessor {
private int counter = 0;
public int process() {
counter++;
return counter;
}
}
このクラスは、注入されるたびに新しいインスタンスが生成されます。 counterの値も、それぞれ独立して管理されます。
4. @Prototypeが新しいインスタンスを生成する仕組み
@Prototypeが付いたクラスは、DIコンテナにキャッシュされません。 そのため、必要になるたびにインスタンスが作成されます。
次の例では、同じクラスを二回注入した場合でも、別のオブジェクトとして扱われます。
import jakarta.inject.Singleton;
@Singleton
public class TaskRunner {
private final TaskProcessor taskProcessor1;
private final TaskProcessor taskProcessor2;
public TaskRunner(TaskProcessor taskProcessor1,
TaskProcessor taskProcessor2) {
this.taskProcessor1 = taskProcessor1;
this.taskProcessor2 = taskProcessor2;
}
public void run() {
System.out.println(taskProcessor1.process());
System.out.println(taskProcessor2.process());
}
}
1
1
出力結果からも分かるように、それぞれのTaskProcessorは別のインスタンスです。 これが@Prototypeの最大の特徴です。
5. @Singletonとの違いを理解する
@Singletonはアプリケーション全体で一つのインスタンスを共有します。 一方で@Prototypeは、使われるたびに新しいインスタンスを作ります。
共通処理やサービスクラスは@Singleton、 一時的な処理や状態を持つクラスは@Prototype、 というように役割で使い分けるのが基本です。 この判断ができるようになると、Micronautの設計が一段と理解しやすくなります。
6. @Prototypeが向いている具体的な場面
@Prototypeは、リクエストごとに異なる処理を行うクラスや、 計算途中の状態を保持するクラスに向いています。 また、短時間しか使わないオブジェクトにも適しています。
初心者のうちは、状態を持つクラスには@Prototypeを使う、 状態を持たないクラスには@Singletonを使う、 というルールを意識すると混乱しにくくなります。
7. @Prototypeを使う際の注意点
@Prototypeは便利ですが、インスタンス生成回数が増える点には注意が必要です。 大量に生成されると、パフォーマンスに影響する場合もあります。
そのため、本当に新しいインスタンスが必要かを考えた上で使うことが大切です。 MicronautのDIは高速ですが、設計の意図を明確にすることが重要です。
まとめ
MicronautとDIスコープの理解を深める総まとめ
Micronautにおける依存性注入の設計を理解するうえで、スコープという考え方は非常に重要なポイントとなります。 特に@Prototypeは、オブジェクトのライフサイクルを柔軟に制御するために欠かせない仕組みであり、アプリケーションの設計品質に大きく関わってきます。 本記事では、Micronaut DIの基本から、@Prototypeの特徴、@Singletonとの違い、実際のコード例を通して、その動作や使いどころを丁寧に解説してきました。
まず理解しておきたいのは、MicronautのDIは単なるオブジェクト生成の仕組みではなく、アプリケーション全体の構造を整理するための設計思想でもあるという点です。 その中でスコープは、オブジェクトがどのタイミングで生成され、どの範囲で共有されるのかを決定する重要な要素です。 @Prototypeは、依存性注入されるたびに新しいインスタンスを生成するという特徴を持ち、状態を持つ処理や一時的なロジックに適したスコープです。
例えば、処理の途中で値を保持するようなクラスや、毎回独立した状態で実行したい処理では、@Singletonではなく@Prototypeを選択することで、安全かつ直感的な設計が可能になります。 @Singletonの場合、インスタンスが共有されるため、意図しない状態の共有が発生するリスクがありますが、@Prototypeではその心配がありません。
サンプルコードで振り返るPrototypeの特徴
import jakarta.inject.Prototype;
@Prototype
public class CounterService {
private int count = 0;
public int increment() {
count++;
return count;
}
}
上記のコードでは、CounterServiceは呼び出されるたびに新しいインスタンスが生成されるため、それぞれのcountは独立した値として管理されます。 つまり、同じクラスであっても、利用箇所ごとに全く別のオブジェクトとして扱われることになります。
import jakarta.inject.Singleton;
@Singleton
public class CounterRunner {
private final CounterService service1;
private final CounterService service2;
public CounterRunner(CounterService service1, CounterService service2) {
this.service1 = service1;
this.service2 = service2;
}
public void run() {
System.out.println(service1.increment());
System.out.println(service2.increment());
}
}
1
1
実行結果からも分かる通り、service1とservice2はそれぞれ別のインスタンスであり、同じ処理を行っても状態は共有されていません。 この動作こそが、@Prototypeの最大の特徴であり、設計上の大きなメリットです。
実務で役立つ使い分けのポイント
実際の開発では、すべてを@Prototypeにするのではなく、用途に応じて適切にスコープを使い分けることが重要です。 一般的な指針としては、共通処理や再利用されるサービスには@Singletonを使用し、状態を持つ処理や一時的な計算処理には@Prototypeを使用します。 この判断ができるようになると、コードの可読性や保守性が大きく向上します。
また、@Prototypeはインスタンス生成の回数が増えるため、パフォーマンスへの影響も考慮する必要があります。 Micronautは高速なDIコンテナを提供していますが、それでも不要なインスタンス生成は避けるべきです。 設計段階で本当に新しいインスタンスが必要かを見極めることが、良いアプリケーションを作るための鍵となります。
生徒
Micronautの@Prototypeについて理解できました。毎回新しいインスタンスが作られるというのが大きなポイントなんですね。
先生
その通りです。特に状態を持つ処理では、@Prototypeを使うことで安全に設計できます。
生徒
@Singletonとの違いもはっきりしました。共有するかしないかで選ぶという考え方ですね。
先生
はい。設計の意図を明確にすることが重要です。どのスコープを使うかで、アプリケーションの振る舞いが大きく変わります。
生徒
インスタンス生成のコストについても意識しないといけないですね。
先生
その視点はとても大切です。便利だからといって乱用せず、必要な場面で適切に使うことがプロの設計です。
生徒
今回の内容でMicronautのDI設計の考え方がかなり理解できました。
先生
良い理解です。この調子でスコープを意識した設計を続けていけば、より実践的な開発力が身についていきます。