🐈

Nest.jsのInjection scopesについて理解する

2023/06/25に公開

背景

社内のプロジェクトで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つのプロバイダ(クラス)を作りました。この時、HogeServiceBazServiceFooServiceに注入されています。そしてHogeServicesomethingというインスタンス変数を持っています。

この時、BazServiceFooServiceに注入されているHogeServiceインスタンスはシングル

トン、つまり、同じものということになります。

BazServiceHogeServicesomethingを変更すると、FooServiceで参照しているsomethingも変更が反映されます。これは、HogeServiceがシングルトンスコープで提供され、BazServiceFooServiceで共有されているからです。

Injection Scopeは変更できる

HogeServiceのスコープをリクエストスコープまたはトランジェントスコープに変更すると、BazServiceFooServiceの間でHogeServiceのインスタンスは共有されず、各サービスで異なる状態を持つことが可能になります。

以下具体的なコードを見ていきます。

もちろんです、以下に追記します:

// hoge.service.ts
import { Injectable, Scope } from '@nestjs/common';

@Injectable({ scope: Scope.REQUEST })
export class HogeService {
  something = 10;
}

上記のようにHogeServiceInjectableデコレータのオプションとして、{ scope: Scope.REQUEST }を指定することで、HogeServiceはリクエストスコープとなります。これにより、HogeServiceのインスタンスは各リクエストごとに新しく作成されます。

したがって、BazServiceFooServiceHogeServicesomethingを変更しても、それぞれが持つHogeServiceインスタンスは別々なので、互いの状態に影響を与えません。

同様に、Scope.TRANSIENTを指定すると、依存性が注入されるたびに新しいHogeServiceインスタンスが作成されます。これは、各依存性の注入が独立した状態を持つことを保証します。

まとめ

このように、Nest.jsのInjection scopesは、依存性注入がどのように機能するか、そしてプロバイダがどのように作成、共有、破棄されるかを制御します。これにより、アプリケーションの振る舞いと性能を最適化するための強力なツールが提供されます。

注目すべきは、スコープの設定はプロバイダの設計とアプリケーションの要件によって異なるため、注意深く選択する必要があるという点です。例えば、シングルトンスコープはアプリケーションの起動時にインスタンス化されるため、初期化に時間がかかるような重いプロバイダには適しています。一方、リクエストスコープやトランジェントスコープは、リクエストごとに新しいインスタンスが作成されるため、軽量で、短いライフサイクルを持つプロバイダに適しています。

:::
さらに詳しい情報は公式ドキュメントをご覧下さい。
:::

Discussion