当前位置:网站首页 > iOS应用开发 > 正文

Web应用开发框架-egg(三)06-基础功能——插件之定义插件、编写插件 & 定时任务 & 自定义启动app

Web应用开发框架-egg(三)06-基础功能——插件之定义插件、编写插件 & 定时任务 & 自定义启动app

插件

插件机制是我们框架的一大特色。它不但可以保证框架核心的足够精简、稳定、高效,还可以促进业务逻辑的复用,生态圈的形成。

  • Koa 已经有了中间件的机制,为啥还要插件呢?
  • 中间件、插件、应用它们之间是什么关系,有什么区别?
为什么要插件

使用 Koa 中间件过程中发现了下面一些问题:

  1. 中间件加载其实是有先后顺序的,但是中间件自身却无法管理这种顺序,只能交给使用者。这样其实非常不友好,一旦顺序不对,结果可能有天壤之别。
  2. 中间件的定位是拦截用户请求,并在它前后做一些事情,例如:鉴权、安全检查、访问日志等等。但实际情况是,有些功能是和请求无关的,例如:定时任务、消息订阅、后台逻辑等等。
  3. 有些功能包含非常复杂的初始化逻辑,需要在应用启动的时候完成。这显然也不适合放到中间件中去实现。
中间件、插件、应用的关系

一个插件其实就是一个『迷你的应用』,和应用(app)几乎一样:

  • 它包含了 Service、中间件、配置、框架扩展等等。
  • 它没有独立的 Router 和 Controller。(插件一般不写业务逻辑)
  • 它没有 plugin.js,只能声明跟其他插件的依赖,而不能决定其他插件的开启与否。
使用插件

插件一般通过 npm 模块的方式进行复用:

npm i egg-mysql --save 

然后需要在应用或框架的 config/plugin.js 中声明:

// config/plugin.js // 使用 mysql 插件 exports.mysql = { 
    enable: true, package: 'egg-mysql', }; 
根据环境配置

同时,我们还支持 plugin.{env}.js 这种模式,会根据运行环境加载插件配置。

// config/plugin.local.js exports.dev = { 
    enable: true, package: 'egg-dev', }; 
引入
  • packagenpm 方式引入,也是最常见的引入方式
  • path 是绝对路径引入,如应用内部抽了一个插件,但还没达到开源发布独立 npm 的阶段,或者是应用自己覆盖了框架的一些插件
// config/plugin.js const path = require('path'); exports.mysql = { 
    enable: true, path: path.join(__dirname, '../lib/plugin/egg-mysql'), }; 
如何写一个插件

你可以直接使用 egg-boilerplate-plugin 脚手架来快速上手。

$ mkdir egg-hello && cd egg-hello $ npm init egg --type=plugin $ npm i 

一个插件其实就是一个『迷你的应用』,下面展示的是一个插件的目录结构,和应用(app)几乎一样。

. egg-hello ├── package.json ├── app.js (可选) ├── agent.js (可选) ├── app │ ├── extend (可选)| ├── helper.js (可选)| ├── request.js (可选)| ├── response.js (可选)| ├── context.js (可选)| ├── application.js (可选)| └── agent.js (可选) │ ├── service (可选) │ └── middleware (可选) │ └── mw.js ├── config | ├── config.default.js │ ├── config.prod.js | ├── config.test.js (可选) | ├── config.local.js (可选) | └── config.unittest.js (可选) └── test └── middleware └── mw.test.js 
  1. 插件没有独立的 router 和 controller。这主要出于几点考虑:
  • 路由一般和应用强绑定的,不具备通用性。
  • 一个应用可能依赖很多个插件,如果插件支持路由可能导致路由冲突。
  • 如果确实有统一路由的需求,可以考虑在插件里通过中间件来实现。
  1. 插件需要在 package.json 中的 eggPlugin 节点指定插件特有的信息:
  • {String} name - 插件名(必须配置),具有唯一性,配置依赖关系时会指定依赖插件的 name。
  • {Array} dependencies - 当前插件强依赖的插件列表(如果依赖的插件没找到,应用启动失败)。
  • {Array} optionalDependencies - 当前插件的可选依赖插件列表(如果依赖的插件未开启,只会 warning,不会影响应用启动)。
  • {Array} env - 只有在指定运行环境才能开启,具体有哪些环境可以参考运行环境。此配置是可选的,一般情况下都不需要配置。
{ 
    "name": "egg-rpc", "eggPlugin": { 
    "name": "rpc", "dependencies": [ "registry" ], "optionalDependencies": [ "vip" ], "env": [ "local", "test", "unittest", "prod" ] } } 
插件能做什么?
  • 扩展内置对象的接口
    • app/extend/request.js - 扩展 Koa#Request 类
    • app/extend/response.js - 扩展 Koa#Response 类
    • app/extend/context.js - 扩展 Koa#Context 类
    • app/extend/helper.js - 扩展 Helper 类
    • app/extend/application.js - 扩展 Application 类
    • app/extend/agent.js - 扩展 Agent 类
  • 插入自定义中间件
  • 在应用启动时做一些初始化工作
  • 设置定时任务
定时任务

会有许多场景需要执行一些定时任务,例如:

  1. 定时上报应用状态。
  2. 定时从远程接口更新本地缓存。
  3. 定时进行文件切割、临时文件删除。

框架提供了一套机制来让定时任务的编写和维护更加优雅。

编写定时任务

所有的定时任务都统一存放在 app/schedule 目录下,每一个文件都是一个独立的定时任务,可以配置定时任务的属性和要执行的方法。

const Subscription = require('egg').Subscription; class LogSubscription extends Subscription { 
    // 通过 schedule 属性来设置定时任务的执行间隔等配置 static get schedule() { 
    return { 
    interval: '1s', // 1 分钟间隔 type: 'worker', // 指定所有的 worker 都需要执行 }; } // subscribe 是真正定时任务执行时被运行的函数 async subscribe() { 
    console.log('我是定时任务') } } module.exports = LogSubscription; 

另一种写法:

module.exports = { 
    schedule: { 
    interval: '1s', // 1 分钟间隔 type: 'all', // 指定所有的 worker 都需要执行 }, async task(ctx) { 
    console.log('我是定时任务') }, }; 
参数
  • interval
    • 数字类型,单位为毫秒数,例如 5000
    • 字符类型,会通过 ms 转换成毫秒数,例如 5s
  • type
    • worker 类型:每台机器上只有一个 worker 会执行这个定时任务,每次执行定时任务的 worker 的选择是随机的。
    • all 类型:每台机器上的每个 worker 都会执行这个定时任务。
自定义启动

我们常常需要在应用启动期间进行一些初始化工作,等初始化完成后应用才可以启动成功,并开始对外提供服务。

框架提供了统一的入口文件(app.js)进行启动过程自定义,这个文件返回一个 Boot 类,我们可以通过定义 Boot 类中的生命周期方法来执行启动应用过程中的初始化工作。

框架提供了这些 生命周期函数供开发人员处理:

  • 配置文件即将加载,这是最后动态修改配置的时机(configWillLoad
  • 配置文件加载完成(configDidLoad
  • 文件加载完成(didLoad
  • 插件启动完毕(willReady
  • worker 准备就绪(didReady
  • 应用启动完成(serverDidReady
  • 应用即将关闭(beforeClose
// app.js class AppBootHook { 
    constructor(app) { 
    this.app = app; } configWillLoad() { 
    // 此时 config 文件已经被读取并合并,但是还并未生效 // 这是应用层修改配置的最后时机 // 注意:此函数只支持同步调用 console.log('configWillLoad') // 例如:参数中的密码是加密的,在此处进行解密 // this.app.config.mysql.password = decrypt(this.app.config.mysql.password); // // 例如:插入一个中间件到框架的 coreMiddleware 之间 // const statusIdx = this.app.config.coreMiddleware.indexOf('status'); // this.app.config.coreMiddleware.splice(statusIdx + 1, 0, 'limit'); } async didLoad() { 
    console.log('didLoad') // 所有的配置已经加载完毕 // 可以用来加载应用自定义的文件,启动自定义的服务 // 例如:创建自定义应用的示例 // this.app.queue = new Queue(this.app.config.queue); // await this.app.queue.init(); // // 例如:加载自定义的目录 // this.app.loader.loadToContext(path.join(__dirname, 'app/tasks'), 'tasks', { 
    // fieldClass: 'tasksClasses', // }); } async willReady() { 
    console.log('willReady') // 所有的插件都已启动完毕,但是应用整体还未 ready // 可以做一些数据初始化等操作,这些操作成功才会启动应用 // 例如:从数据库加载数据到内存缓存 // this.app.cacheData = await this.app.model.query(QUERY_CACHE_SQL); } async didReady() { 
    console.log('didReady') // 应用已经启动完毕 // const ctx = await this.app.createAnonymousContext(); // await ctx.service.Biz.request(); } async serverDidReady() { 
    console.log('serverDidReady') // http / https server 已启动,开始接受外部请求 // 此时可以从 app.server 拿到 server 的实例 // this.app.server.on('timeout', socket => { 
    // // handle socket timeout // }); } } module.exports = AppBootHook; 

注意:在自定义生命周期函数中不建议做太耗时的操作,框架会有启动的超时检测。

到此这篇Web应用开发框架-egg(三)06-基础功能——插件之定义插件、编写插件 & 定时任务 & 自定义启动app的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • Web应用开发框架-egg(四)——egg总结之egg快速入门、内置对象、运行环境、config配置、中间件、路由、控制器、服务service、插件、定时任务、自定义启动2024-12-02 18:00:07
  • Web应用开发框架-egg进阶与实战(一)——debug调试步骤、日志之日志路径、日志分类、日志级别、如何打印日志、文件日志级别、日志切割、日志影响性能2024-12-02 18:00:07
  • Web应用开发框架-egg进阶与实战(三)——总结之debug、日志、多进程、错误处理、多实例插件、多进程增强、实战-简易博客2024-12-02 18:00:07
  • ios正式包ipa,发布苹果应用商店App Store2024-12-02 18:00:07
  • java ios开发_使用Java开发iOS应用_java做ios开发2024-12-02 18:00:07
  • Web应用开发框架-egg(三)04-基础功能——路由之定义Router、restful风格的URL定义、获取路由参数2024-12-02 18:00:07
  • Web应用开发框架-egg(三)03-基础功能——中间件之编写中间件、中间件的配置、使用中间件、在框架和插件中使用中间件 & 中间件的通用配置项2024-12-02 18:00:07
  • Web应用开发框架-egg(三)02-基础功能——运行环境 & Config配置之多环境配置、配置写法、配置加载顺序、合并规则、配置结果2024-12-02 18:00:07
  • Web应用开发框架-egg(三)01-基础功能——目录结构的约定之框架规定的目录、内置插件约定的目录 & 内置对象之Application、context、Request & Response等2024-12-02 18:00:07
  • Web应用开发框架-egg(二)——快速入门之模板渲染、编写helper扩展、编写Middleware、渐进式开发 & egg总结2024-12-02 18:00:07
  • 全屏图片