LoopBack4控制器中如何获取应用实例及全局单例对象?
刚好对LoopBack 4的依赖注入体系比较熟悉,我来给你梳理下在不同组件里访问全局/单例对象的所有常用方式,从你提到的控制器场景展开,再覆盖仓库、模型等组件:
一、控制器中访问核心对象的方式
你已经通过注入RestBindings.Http.CONTEXT拿到了请求级别的Context,这是个不错的方式,从这个Context里还能直接取出request和response对象:
import {RestBindings} from '@loopback/rest'; import {Context} from '@loopback/core'; export class TodoController { constructor( @repository(TodoRepository) public todoRepository: TodoRepository, @inject(RestBindings.Http.CONTEXT) public ctx: Context, ) {} async someAction() { const request = await this.ctx.get(RestBindings.Http.REQUEST); const response = await this.ctx.get(RestBindings.Http.RESPONSE); // 修改状态码 response.status(201); return {message: 'Done'}; } }
不过更直接的方式是直接注入request和response,不用先获取Context:
import {Request, Response} from '@loopback/rest'; export class TodoController { constructor( @repository(TodoRepository) public todoRepository: TodoRepository, @inject(RestBindings.Http.REQUEST) public request: Request, @inject(RestBindings.Http.RESPONSE) public response: Response, ) {} async createTodo(@requestBody() todo: Todo) { const created = await this.todoRepository.create(todo); // 直接设置状态码 this.response.status(201); return created; } }
另外,修改返回状态码还有更优雅的方式——用@status()装饰器或者在API spec里定义:
import {post, requestBody, status} from '@loopback/rest'; @post('/todos') @status(201) // 直接指定返回状态码 async create(@requestBody() todo: Todo): Promise<Todo> { return this.todoRepository.create(todo); }
如果要访问Application全局实例,控制器里可以注入CoreBindings.APPLICATION_INSTANCE:
import {CoreBindings, Application} from '@loopback/core'; export class TodoController { constructor( @inject(CoreBindings.APPLICATION_INSTANCE) public app: Application, ) {} async getAppInfo() { return {appName: this.app.options.name}; } }
二、仓库中访问全局/单例对象
仓库属于数据访问层,本身和HTTP上下文无关,所以不能直接注入request/response,但可以注入全局Context或者Application实例来获取全局配置、单例服务等:
import {CoreBindings, Application, Context} from '@loopback/core'; import {DefaultCrudRepository} from '@loopback/repository'; export class TodoRepository extends DefaultCrudRepository< Todo, typeof Todo.prototype.id, TodoRelations > { constructor( @inject('datasources.db') dataSource: DbDataSource, // 注入Application实例 @inject(CoreBindings.APPLICATION_INSTANCE) public app: Application, // 或者注入全局Context @inject(CoreBindings.CONTEXT) public ctx: Context, ) { super(Todo, dataSource); } async getGlobalConfig() { // 从Context获取自定义全局配置 const config = await this.ctx.get('config.todo.defaultLimit'); return config; } }
不过要注意:仓库尽量保持职责单一,只处理数据操作,除非确实需要依赖全局资源,否则不建议注入过多外部对象。
三、模型中访问全局对象
LoopBack 4的模型主要是定义数据结构和验证规则,属于纯数据层,不建议在模型里注入依赖(会破坏模型的纯净性,增加耦合)。如果确实需要访问全局资源,推荐两种方式:
- 把需要的资源作为参数传入模型的方法(比如静态方法)
- 在控制器/服务里处理逻辑,再把结果传给模型
举个静态方法的示例:
import {model, property} from '@loopback/repository'; import {Context} from '@loopback/core'; @model() export class Todo extends Entity { @property({type: 'number', id: true, generated: true}) id?: number; @property({type: 'string', required: true}) title: string; // 通过参数传入Context获取全局配置 static async getDefaultTitle(ctx: Context): Promise<string> { return ctx.get('config.todo.defaultTitle'); } }
四、通用依赖注入规则(所有DI组件)
LoopBack 4的核心是依赖注入(DI),所有被DI容器管理的组件(控制器、仓库、服务、拦截器等)都可以通过@inject()装饰器获取绑定的对象:
- 全局Context:
@inject(CoreBindings.CONTEXT) - Application实例:
@inject(CoreBindings.APPLICATION_INSTANCE) - HTTP请求级对象(仅控制器等HTTP上下文组件可用):
RestBindings.Http.REQUEST、RestBindings.Http.RESPONSE、RestBindings.Http.CONTEXT - 自定义单例服务:如果你的服务用
@injectable()装饰,可以直接注入,比如@inject(MyService) public myService: MyService
总结一下
- 控制器:可以直接注入request/response、请求Context、Application,修改状态码用直接操作response或
@status()装饰器都很方便 - 仓库:可注入全局Context/Application,但尽量避免依赖HTTP相关对象
- 模型:保持纯净,尽量通过参数传递外部资源,不要直接注入依赖
- 所有DI组件都能通过
@inject()获取绑定的全局/单例对象,核心绑定参考CoreBindings和RestBindings
内容的提问来源于stack exchange,提问作者hazimdikenli
相关产品推荐
相关产品推荐

