一、基礎注入方式
1. 構造函數注入(Constructor Injection)
適用場景:模塊間依賴傳遞,服務初始化時必須存在的依賴
實現方式:通過構造函數參數聲明依賴,NestJS 自動解析并注入
@Injectable()
class UserService {constructor(private readonly logger: LoggerService) {} // 自動注入 LoggerServicegetUser() {this.logger.log('Fetching user data');// 業務邏輯}
}
2. 屬性注入(Property Injection)
適用場景:可選依賴或動態注入場景
實現方式:使用 @Inject()
裝飾器配合自定義 Token
@Injectable()
class OrderService {@Inject('PAYMENT_GATEWAY') // 自定義 Tokenprivate paymentGateway: PaymentService;processPayment() {this.paymentGateway.charge(); // 動態注入的支付網關}
}
二、高級注入模式
3. 值提供者(Value Provider)
適用場景:注入配置常量、第三方庫實例
實現方式:通過 useValue
定義固定值
@Module({providers: [{provide: 'API_KEY',useValue: '12345-ABCDE', // 硬編碼 API Key},{provide: 'EXTERNAL_SDK',useValue: new ThirdPartySDK(), // 注入第三方實例}]
})
class ConfigModule {}
4. 類提供者(Class Provider)
適用場景:根據環境動態切換實現類
實現方式:使用 useClass
指定具體類
@Module({providers: [{provide: 'ConfigService',useClass: process.env.NODE_ENV === 'prod' ? ProdConfigService : DevConfigService,}]
})
class AppModule {}
5. 工廠提供者(Factory Provider)
適用場景:需要運行時計算或組合依賴的場景
實現方式:通過 useFactory
動態創建實例
@Module({providers: [{provide: 'DatabaseConnection',useFactory: async (configService: ConfigService) => {const config = await configService.getDatabaseConfig();return createConnection(config);},inject: [ConfigService], // 注入其他依賴}]
})
class DatabaseModule {}
6. 異步提供者(Async Provider)
適用場景:處理異步初始化操作(如數據庫連接)
實現方式:結合 useFactory
與 async/await
@Module({providers: [{provide: 'RedisClient',useFactory: async () => {const client = createClient({ url: 'redis://localhost:6379' });await client.connect();return client;},}]
})
class CacheModule {}
7. 多提供者(Multi Provider)
適用場景:插件系統、中間件集合等需要多個同類實現的場景
實現方式:設置 multi: true
標記
@Module({providers: [{provide: 'EventListeners',useClass: OrderListener,multi: true,},{provide: 'EventListeners',useClass: PaymentListener,multi: true,}]
})
class EventModule {}
三、最佳實踐與常見問題
1. 模塊化設計原則
- 單一職責模塊:每個模塊聚焦特定功能領域(如
UserModule
、AuthModule
) - 跨模塊依賴:通過
exports
暴露服務,避免循環導入@Module({providers: [UserService],exports: [UserService], // 其他模塊可注入 UserService }) class UserModule {}
2. 測試優化策略
- 模擬依賴:使用
@nestjs/testing
創建隔離測試環境const module = await Test.createTestingModule({providers: [UserService,{ provide: LoggerService, useValue: mockLogger },], }).compile();
3. 性能優化技巧
- 延遲加載:對非關鍵依賴使用
@LazyInject()
(需第三方庫支持) - 作用域控制:通過
@Injectable({ scope: Scope.TRANSIENT })
管理實例生命周期
4. 常見問題解析
- 循環依賴:使用
forwardRef()
打破循環@Module({imports: [forwardRef(() => OrderModule)], }) class UserModule {}
- Token 沖突:優先使用類名作為 Token,避免字符串 Token 重復
四、實戰案例:TypeORM 集成
@Module({imports: [TypeOrmModule.forRootAsync({useFactory: (config: ConfigService) => ({type: 'postgres',url: config.get('DATABASE_URL'),entities: [__dirname + '/**/*.entity{.ts,.js}'],}),inject: [ConfigService],}),TypeOrmModule.forFeature([UserEntity]),],providers: [UserService],
})
class UserModule {}@Injectable()
class UserService {constructor(@InjectRepository(UserEntity)private userRepo: Repository<UserEntity>,) {}async findUser(id: string) {return this.userRepo.findOne(id);}
}
五、總結
NestJS 的依賴注入系統通過多樣化的注入方式和靈活的提供者配置,為開發者提供了強大的架構設計能力。從基礎的構造函數注入到復雜的工廠提供者,每種模式都針對特定場景進行了優化。掌握這些模式后,開發者可以:
- 實現模塊間低耦合設計
- 提升代碼可測試性與可維護性
- 動態適配不同運行環境
- 構建可擴展的插件化架構
建議在實際項目中結合具體場景選擇注入方式,并利用 NestJS 的模塊化特性構建清晰的應用架構。