对象全解析:logger、db、resourceManager、acl 等核心成员与插件实战)
NocoBase 服务端 Applicationapp对象全解析logger、db、resourceManager、acl 等核心成员与插件实战【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobaseApplication应用中常以app引用是 NocoBase 服务端运行时的心脏也是插件开发中使用频率最高的对象。无论你是要操作数据库、注册接口、配置权限、注册定时任务还是扩展 CLI 命令几乎都要通过app上暴露的成员来完成。本文以官方插件开发文档 服务端 Application 应用实例 为主线结合 application.ts 源码逐一剖析logger、db、resourceManager、acl、cacheManager、cronJobManager、i18n、cli、dataSourceManager、pm等核心成员的作用、底层实现与典型用法让你在编写插件时对app得心应手。app 是什么从源码看 Application 类在插件中常见的this.app类型是Application它定义于 packages/core/server/src/application.ts。从源码可以看出Application继承自Koa因此它本身就是一个 Web 应用实例具备use()、callback()等中间件能力并通过 Toposort 对中间件进行有序编排它通过applyMixins(Application, [AsyncEmitter])混入了AsyncEmitter支持emitAsync异步事件插件与核心之间的大量协作依赖这套事件机制它聚合了数据库、资源、权限、缓存、定时任务、国际化、CLI、插件管理等子系统并将它们以只读 getter的形式暴露给插件使用。在插件类 plugin.ts 中构造函数会保存this.app app并直接提供this.log、this.db、this.pm、this.ai等便捷 getter内部均委托给this.app例如get log() { return this.app.log.child({ reqId: this.app.context.reqId, module: this.name, }); } get db() { return this.app.db; } get pm() { return this.app.pm; }因此下面的两种写法是等价的this.db与this.app.db、this.log与this.app.log。接下来我们按文档列出的顺序逐一深入每个成员。logger系统日志与请求日志app.logger是 NocoBase 的系统日志器SystemLogger在 application.ts 中通过get logger()暴露同时提供了app.log作为别名L324插件内最常见的用法就是this.log.info(...)、this.log.error(...)。底层由 initLogger 初始化创建了三类日志日志对象文件用途app.log/app.loggersystem系统级日志按appName目录存放seperateError: true表示错误单独输出app.requestLoggerrequest每次 HTTP 请求的访问日志app.sqlLoggersqlSQL 执行日志级别为debug仅当数据库开启logging时写入所有日志文件统一存放在getLoggerFilePath(this.name)对应的目录下main应用即storage/logs/main/一类路径。日志对象还会自动带上reqId请求 ID、app应用名、module模块名等上下文字段便于在多应用、多请求场景下检索。插件中如果需要独立的子日志器可以直接通过app.createLogger(options)创建L1164也可参照 Plugin 类用this.app.log.child({ module: this.name })派生带模块标识的子 logger。db主数据源对应的 Database 实例app.db是插件开发中最常用的成员之一用于 CRUD、事务、定义集合、监听数据库事件等。需要特别注意的是它的取值逻辑L362get db(): Database { if (!this.mainDataSource) { return null; } return this.mainDataSource.collectionManager.db; }也就是说app.db并不是一个独立字段而是「main 数据源」的 collectionManager 所持有的 SequelizeDatabase实例mainDataSource见 L358。这也体现了 NocoBase 多数据源的架构app.db始终指向主数据源而其他数据源需要通过app.dataSourceManager访问下文详述。在真实插件中app.db的典型用法包括// 获取仓库Repository执行查询 const role await this.app.db.getRepository(roles).findOne({ filter: { name: admin } }); // 注册自定义模型 this.app.db.registerModels({ ... }); // 监听数据库事件 this.app.db.on(roles.afterSaveWithAssociations, async (model, options) { ... });以上用法均可在 plugin-acl 服务端实现 中找到对应代码。更多 CRUD、事务、集合定义内容参见 Database 数据库 与 Collections 数据表。resourceManager资源与接口注册app.resourceManager用于注册资源resource与动作action是插件暴露自定义接口的核心入口。源码 L371 显示它同样来自主数据源get resourceManager() { return this.mainDataSource.resourceManager; }它底层是nocobase/resourcer包的Resourcer实例由 createResourcer 创建。应用初始化时还通过 registerActions 批量注册了create/update/destroy/get/list等内置动作。插件中的典型用法以 plugin-acl 为例server.ts// 注册资源中间件 this.app.resourceManager.use(setCurrentRole, { tag: setCurrentRole, before: acl, after: auth }); // 注册/覆盖动作处理器 this.app.resourceManager.registerActionHandlers({ ... });注意文档与源码中还存在app.resourcer这一旧名称它已被标记为deprecatedL380新代码应统一使用app.resourceManager。详见 ResourceManager 资源管理。acl权限控制app.acl是主数据源的 ACLAccess Control List实例L421get acl() { return this.mainDataSource.acl; }它由 createACL() 创建支持角色、权限片段snippet、动作别名等功能。plugin-acl 插件中的实际用法// 注册权限片段 this.app.acl.registerSnippet({ ... }); // 放行指定资源与动作loggedIn 表示登录用户可访问 this.app.acl.allow(users, setDefaultRole, loggedIn); this.app.acl.allow(*, *, (ctx) { ... }); // 为动作附加固定过滤参数 this.app.acl.addFixedParams(collections, destroy, () { ... });以上代码见 plugin-acl server.ts。数据源添加时会自动把availableActions注册进各数据源的 ACLapplication.ts L1324-L1330。更多细节参见 ACL 权限控制。cacheManager缓存管理app.cacheManager是缓存管理器CacheManagerapp.cache则是默认缓存实例。源码 L384-L394 定义了两个 getterget cacheManager() { return this._cacheManager; } get cache() { return this._cache; }缓存管理器由 createCacheManager 创建创建时会以prefix: this.name作为缓存键前缀避免多应用之间键冲突async createCacheManager() { this._cacheManager await createCacheManager(this, { prefix: this.name, ...this.options.cacheManager, }); return this._cacheManager; }在应用load()过程中L682-L685缓存管理器会被重新创建因此在beforeLoad之后访问app.cacheManager才是安全的。插件的典型用法是this.app.cache.get(key)/this.app.cache.set(key, value)详见 Cache 缓存。cronJobManager定时任务app.cronJobManager是 NocoBase 的定时任务管理器底层基于cron库实现源码位于 packages/core/server/src/cron/cron-job-manager.ts。核心 API 如下public addJob(options: CronJobParameters) { const cronJob new CronJob(options); this._jobs.add(cronJob); return cronJob; } public removeJob(job: CronJob) { job.stop(); this._jobs.delete(job); } public start() { /* 启动所有任务 */ } public stop() { /* 停止所有任务 */ }值得关注的是它的生命周期绑定cron-job-manager.ts L18-L30应用beforeStop时自动stop()所有任务应用afterStart时自动start()所有任务应用beforeReload时自动停止。因此在插件中通过addJob注册的定时任务会跟随应用启停通常无需手动调用start()/stop()。插件注册定时任务的示例摘自 CronJobManager 定时任务import { Plugin } from nocobase/server; export default class PluginCronDemo extends Plugin { async load() { this.app.cronJobManager.addJob({ cronTime: 0 0 * * *, // 每天 00:00 执行 onTick: async () { console.log(每日任务清理临时数据); await this.cleanTemporaryData(); }, timeZone: Asia/Shanghai, start: true, // 自动启动 }); } async cleanTemporaryData() { // 在此执行清理逻辑 } }CronJobParameters支持cronTime、onTick、onComplete、timeZone、context、runOnInit、utcOffset、unrefTimeout等参数常用 cron 表达式包括* * * * *每分钟、0 0 * * *每天 00:00、0 9 * * 1每周一 09:00、*/10 * * * *每 10 分钟。完整参数表见 cron-job-manager.md。i18n国际化app.i18n是 NocoBase 服务端的 i18next 实例由 createI18n 创建export function createI18n(options: ApplicationOptions) { const instance i18next.createInstance(); instance.init({ lng: process.env.INIT_LANG || en-US, resources: {}, keySeparator: false, nsSeparator: false, ...options.i18n, }); return instance; }要点默认语言来自环境变量INIT_LANG否则回退为en-US关闭了keySeparator与nsSeparator即翻译键中允许出现.与:而不被 i18next 当作分隔符解析可通过ApplicationOptions.i18n覆盖初始化选项。插件中通常使用this.t(key)进行翻译Plugin 类内部实现为plugin.ts L272t(text: TFuncKey | TFuncKey[], options: TOptions {}) { return this.app.i18n.t(text, { ns: this.options[packageName], ...(options as any) }); }即默认以插件包名作为命名空间namespace。多语言资源加载细节参见 I18n 国际化。cli扩展命令行app.cli是应用的命令行解析器类型为AppCommand封装自commander。在 createCLI 中可以看到它以nocobase为根命令名通过preAction/postAction钩子完成命令执行的收尾并在执行前按需调用authenticate()与load()。插件注册自定义命令有两种方式// 方式一在插件 load 中通过 app.cli 注册 app.cli.command(my-command).action(async () { ... }); // 方式二使用 app.command 便捷方法application.ts L596 app.command(my-command, 命令描述).action(async () { ... });app.command()内部即this.cli.command(...).allowUnknownOption()。CLI 命令的完整写法、参数解析参见 Command 命令行。dataSourceManager多数据源管理app.dataSourceManager管理 NocoBase 的所有数据源。与app.db仅主数据源不同通过它可以访问、注册任意数据源application.ts L467-L471。在真实插件中的用法来自 plugin-action-custom-request 与 plugin-acl 测试// 按 key 获取数据源 const dataSource app.dataSourceManager.get(dataSourceKey || main); // 注册新的数据源类型 app.dataSourceManager.factory.register(sequelize, SequelizeDataSource); // 动态添加数据源 await app.dataSourceManager.add(dataSource); // 监听数据源添加事件在插件中为每个数据源注入能力 this.app.dataSourceManager.afterAddDataSource((dataSource) { ... }); this.app.dataSourceManager.beforeAddDataSource((dataSource) { ... });插件中常见的做法是结合afterAddDataSource事件为每个新接入的数据源同步注册资源动作或 ACL 可用动作NocoBase 核心自身也是这么做的见 application.ts L1319-L1330。详见 DataSourceManager 数据源管理。pm插件管理器app.pm是PluginManager实例负责插件的加载、安装、启用、停用与升级。源码 L415-L419get pm() { return this._pm; }插件开发中常见的使用场景// 获取其他插件实例 const otherPlugin this.app.pm.get(nocobase/plugin-acl); // 注册预设插件 this.app.pm.addPreset(PluginClass, options); // 执行插件命令 await this.app.pm.install();另外Application.plugin()已被标记为deprecated官方建议改用this.app.pm.addPreset()application.ts L539-L542。插件生命周期与管理命令yarn pm create/pull/enable/disable/remove参见 插件开发概述。补充成员文档之外值得了解的 app 能力除了文档列出的十大成员从 application.ts 中还可以看到其他实用成员按需使用成员类型说明app.authManagerAuthManager认证管理器默认authKey: X-Authenticator、默认认证器basicL1306-L1310app.auditManagerAuditManager审计日志管理器app.environmentEnvironment环境管理app.versionApplicationVersion应用版本信息app.getPackageVersion()获取包版本app.telemetryTelemetry遥测通过options.telemetry.enabled控制是否采集app.localeManager/app.localesLocale语言资源管理locales已废弃app.containerServiceContainer服务容器用于依赖注入app.eventQueue、app.lockManager、app.pubSubManager、app.syncMessageManager-事件队列、分布式锁、发布订阅、跨实例消息同步app.aiManagerAIManagerAI 能力管理工具、技能、AI 员工等插件中通过this.ai访问app.mainDataSourceSequelizeDataSource主数据源实例app.db与app.resourceManager均由其派生这些成员均在Application.init()application.ts L1244中完成初始化因此插件在load()阶段之后都可以安全访问。总结app 成员的访问时机与最佳实践综合文档与源码使用app时建议遵循以下实践在load()之后使用运行时能力cacheManager、db、resourceManager等在应用加载流程中才会就绪插件应在load()、install()等生命周期方法中访问而非插件构造函数中。主数据源优先用app.db多数据源用app.dataSourceManager两者语义不同前者永远指向main数据源。使用新 API 而非废弃别名用resourceManager代替resourcer用pm.addPreset()代替plugin()用localeManager代替locales。定时任务无需手动启停cronJobManager已自动跟随应用生命周期beforeStop/afterStart/beforeReload。日志优先使用this.log插件基类已为日志附加reqId与module上下文便于排查问题。相关参考应用生命周期与事件见 Event 事件ctx.app在请求上下文中的使用见 Context 上下文编写测试时如何创建 app 实例见 Test 测试。【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考