Nest.jsのInjection scopesについて理解する
背景
社内のプロジェクトでNest.jsを使っていて、各クラスのインスタンス変数のスコープについて気になって調べたので、アウトプットしていく。
Next.jsのDI(依存性注入)の仕組みについて気になる人はNest.jsの公式ドキュメントをご覧ください。
Injection scopesについて
Nest.jsの"Injection scopes"は、依存性注入が行われる際のプロバイダ(サービスやリポジトリなど)の生存期間と可視性を指します。これは新しいインスタンスが作成されるタイミングと、そのインスタンスが共有される範囲を決定します。
Nest.jsのInjection scopesはデフォルトではシングルトンとなっています。つまり、アプリケーションが起動した段階で、全てのプロバイダはインスタンス化され、アプリケーション全体で一意の状態をとるということです。そしてアプリケーションが終了すると、プロバイダのインスタンスも破棄されます。
しかし、必要に応じてプロバイダのスコープを変更することも可能です。これにより、プロバイダはシングルトンスコープでなく、リクエストスコープまたはトランジェントスコープにすることができます。これらのスコープでは、新しいリクエストや依存性の注入ごとに新しいインスタンスが作成されます。
それでは、具体的なコード例を通じてこの概念を理解しましょう。
// hoge.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class HogeService {
something = 10;
}
// baz.service.ts
import { Injectable } from '@nestjs/common';
import { HogeService } from './hoge.service';
@Injectable()
export class BazService {
constructor(private hogeService: HogeService) {}
}
// foo.service.ts
import { Injectable } from '@nestjs/common';
import { HogeService } from './hoge.service';
@Injectable()
export class FooService {
constructor(private hogeService: HogeService) {}
}
上記のような3つのプロバイダ(クラス)を作りました。この時、HogeService
がBazService
とFooService
に注入されています。そしてHogeService
はsomething
というインスタンス変数を持っています。
この時、BazService
とFooService
に注入されているHogeService
インスタンスはシングル
トン、つまり、同じものということになります。
BazService
でHogeService
のsomething
を変更すると、FooService
で参照しているsomething
も変更が反映されます。これは、HogeService
がシングルトンスコープで提供され、BazService
とFooService
で共有されているからです。
Injection Scopeは変更できる
HogeService
のスコープをリクエストスコープまたはトランジェントスコープに変更すると、BazService
とFooService
の間でHogeService
のインスタンスは共有されず、各サービスで異なる状態を持つことが可能になります。
以下具体的なコードを見ていきます。
もちろんです、以下に追記します:
// hoge.service.ts
import { Injectable, Scope } from '@nestjs/common';
@Injectable({ scope: Scope.REQUEST })
export class HogeService {
something = 10;
}
上記のようにHogeService
のInjectable
デコレータのオプションとして、{ scope: Scope.REQUEST }
を指定することで、HogeService
はリクエストスコープとなります。これにより、HogeService
のインスタンスは各リクエストごとに新しく作成されます。
したがって、BazService
とFooService
でHogeService
のsomething
を変更しても、それぞれが持つHogeService
インスタンスは別々なので、互いの状態に影響を与えません。
同様に、Scope.TRANSIENT
を指定すると、依存性が注入されるたびに新しいHogeService
インスタンスが作成されます。これは、各依存性の注入が独立した状態を持つことを保証します。
まとめ
このように、Nest.jsのInjection scopesは、依存性注入がどのように機能するか、そしてプロバイダがどのように作成、共有、破棄されるかを制御します。これにより、アプリケーションの振る舞いと性能を最適化するための強力なツールが提供されます。
注目すべきは、スコープの設定はプロバイダの設計とアプリケーションの要件によって異なるため、注意深く選択する必要があるという点です。例えば、シングルトンスコープはアプリケーションの起動時にインスタンス化されるため、初期化に時間がかかるような重いプロバイダには適しています。一方、リクエストスコープやトランジェントスコープは、リクエストごとに新しいインスタンスが作成されるため、軽量で、短いライフサイクルを持つプロバイダに適しています。
:::
さらに詳しい情報は公式ドキュメントをご覧下さい。
:::
Discussion