Skip to content
第 170 / 250 章Node⏱ 10 分钟阅读

第 170 章:模块(Module)与依赖注入

学习目标

  • 理解模块化架构
  • 掌握 @Module 装饰器
  • 学会依赖注入(DI)三种方式
  • 理解 Provider 作用域

一、模块基础

typescript
import { Module } from '@nestjs/common';

@Module({
  imports: [],        // 导入其他模块
  controllers: [],    // 控制器
  providers: [],      // 服务 / 工具
  exports: [],        // 导出给其他模块用
})
export class UserModule {}

二、特性模块(Feature Module)

bash
# 用 CLI 生成
nest g module user
nest g controller user
nest g service user
src/
├── user/
│   ├── user.module.ts
│   ├── user.controller.ts
│   └── user.service.ts
typescript
// user.module.ts
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';

@Module({
  controllers: [UserController],
  providers: [UserService],
  exports: [UserService],   // 导出,让其他模块能用
})
export class UserModule {}
typescript
// app.module.ts
import { UserModule } from './user/user.module';

@Module({
  imports: [UserModule, OrderModule, AuthModule],
})
export class AppModule {}

三、依赖注入(DI)

3.1 构造器注入(推荐)

typescript
@Controller('users')
export class UserController {
  // ① 构造器注入
  constructor(private readonly userService: UserService) {}

  @Get()
  findAll() {
    return this.userService.findAll();
  }
}

3.2 属性注入

typescript
@Controller('users')
export class UserController {
  @Inject(UserService)
  private readonly userService!: UserService;
}

3.3 可选依赖

typescript
import { Optional, Inject } from '@nestjs/common';

@Controller('users')
export class UserController {
  constructor(
    @Optional() private readonly logger?: LoggerService,
  ) {}
}

四、Provider 类型

typescript
@Module({
  providers: [
    // 1. 简写
    UserService,

    // 2. 完整写法
    {
      provide: UserService,
      useClass: UserService,
    },

    // 3. 值
    {
      provide: 'CONFIG',
      useValue: { apiKey: 'xxx' },
    },

    // 4. 工厂
    {
      provide: 'DATABASE',
      useFactory: () => ({
        host: 'localhost',
        port: 5432,
      }),
    },

    // 5. 别名
    {
      provide: 'AliasService',
      useExisting: UserService,
    },
  ],
})
export class UserModule {}

五、自定义 Provider 注入

typescript
// 注入值
constructor(@Inject('CONFIG') private config: any) {}

// 注入工厂
constructor(@Inject('DATABASE') private db: any) {}

六、模块的 exports

只有 exports 数组里的 Provider 才能被其他模块用。

typescript
// user.module.ts
@Module({
  providers: [UserService, UserRepository],
  exports: [UserService],   // ① 只导出 UserService
})
export class UserModule {}

// order.module.ts
@Module({
  imports: [UserModule],     // ② 导入
  controllers: [OrderController],
  providers: [OrderService],
})
export class OrderModule {}

// order.service.ts
@Injectable()
export class OrderService {
  // ✅ 可以注入,因为 UserService 被导出
  constructor(private userService: UserService) {}
}

七、全局模块

typescript
@Global()   // ① 全局,无需 imports
@Module({
  providers: [ConfigService],
  exports: [ConfigService],
})
export class ConfigModule {}
typescript
@Module({
  imports: [ConfigModule],  // 仍要 import,但不需要每个用到的地方都 import
})
export class UserModule {}

八、动态模块

typescript
@Module({})
export class DatabaseModule {
  static forRoot(options: DbOptions): DynamicModule {
    return {
      module: DatabaseModule,
      providers: [
        {
          provide: 'DB_OPTIONS',
          useValue: options,
        },
        DatabaseService,
      ],
      exports: [DatabaseService],
      global: true,
    };
  }
}
typescript
// app.module.ts
@Module({
  imports: [
    DatabaseModule.forRoot({
      host: 'localhost',
      port: 5432,
    }),
  ],
})
export class AppModule {}

九、Provider 作用域

typescript
// 默认:单例
@Injectable()
export class UserService {}

// 请求作用域(每个请求一个新实例)
@Injectable({ scope: Scope.REQUEST })
export class UserService {}

// 瞬态(每次注入都新实例)
@Injectable({ scope: Scope.TRANSIENT })
export class UserService {}

十、循环依赖

typescript
// a.service.ts
@Injectable()
export class AService {
  constructor(@Inject(forwardRef(() => BService)) private b: BService) {}
}

// b.service.ts
@Injectable()
export class BService {
  constructor(@Inject(forwardRef(() => AService)) private a: AService) {}
}

十一、本章小结

概念关键
@Module装饰器定义模块
imports引入其他模块
providers注册可注入类
exports让其他模块用
@Global全局模块
构造器注入推荐方式
循环依赖forwardRef

动手练习

  1. 创建 user / order 两个模块
  2. 在 order 中使用 user 的 Service
  3. 创建一个全局 ConfigModule
  4. 用 useFactory 注入一个配置对象

推荐阅读


下一章:第 171 章:Provider 与 Service

本站基于 VitePress 构建 · 由 Codebook 团队维护