目录

为什么说Egg.js是企业级Node框架

说Egg.js是企业级Node框架的原因:1、插件机制;2、MVC架构;3、插件化思想;4、面向对象编程;5、开发规范;6、可拔插性。插件机制是指Egg.js提供了丰富的插件,使得项目开发更加高效。

一、说Egg.js是企业级Node框架的原因

1、插件机制

Egg.js提供了丰富的插件,使得项目开发更加高效,例如可以使用Egg.js内置的egg-mongoose插件来快速集成MongoDB,或使用egg-jwt插件来快速实现JWT的验证和生成。

2、MVC架构

Egg.js采用MVC(Model-View-Controller)模式,使得代码结构清晰,易于维护和扩展。

3、插件化思想

Egg.js通过将常用功能进行封装和组合,让业务开发者只需关注业务逻辑,可以快速完成复杂的开发任务。

4、面向对象编程

Egg.js支持ES6的语法,具备面向对象编程的优点,包括更加灵活和易于维护。

5、开发规范

Egg.js采用一系列的开发规范,包括代码风格、命名规范、异常处理等,使得开发者能够更好地协同开发和代码维护。

6、可拔插性

Egg.js采用插件机制,支持按需加载,可在不影响整个项目运行的情况下增加或删除某些功能,让应用更加灵活。

二、Egg.js是什么

egg.js 是『约定优先于配置』的一个 Node.js web 框架。Egg 奉行『约定优于配置』,按照一套统一的约定进行应用开发,团队内部采用这种方式可以减少开发人员的学习成本,开发人员不再是『钉子』,可以流动起来。没有约定的团队,沟通成本是非常高的,比如有人会按目录分栈而其他人按目录分功能,开发者认知不一致很容易犯错。但约定不等于扩展性差,相反 Egg 有很高的扩展性,可以按照团队的约定定制框架。使用 Loader 可以让框架根据不同环境定义默认配置,还可以覆盖 Egg 的默认约定。

1、架构概览

根据egg.js目录结构先了解其项目规范,为了了解这些目录/文件是做什么,先从我们最熟悉的request讲起:

绿色虚线框中的所有组件组成了一个Worker,这就是egg.js中实际执行代码逻辑的进程,是一个node服务器。

  • request进来后,先穿过中间件,自己定义的中间件都放在projectDir/app/middleware下,并在config中启用。
  • egg.js内置了egg-static中间件,将静态资源放在projectDir/app/public中,只会经过egg-static中间件之前的中间件,最后egg-static直接响应给客户端,不会到达其后的中间件以及Router。
  • 如果不是public中的资源,将会穿越所有中间件,到达路由。一般所有的路由都放在router.js中,这个文件没有任何逻辑,而是直接指向一个处理请求的controller,只起到目录和索引的作用:router.get(‘/users’, controller.user.getAll);
  • Controller都放在projectDir/app/controller中,不含有具体的业务逻辑,业务逻辑都在Service中,Controller只负责调用并组合Service,最后将响应提交给客户端。
  • Service放在projectDir/app/service中,负责调用Model,进行具体业务。
  • 除此之外,Worker中还有定时任务,写在projectDir/app/schedule文件夹中。
  • 各个部件的所有可操控行为,都可以在projectDir/confg/中的配置文件中定义,配置文件可以同时有很多份,default会被具体环境的配置文件中的同名字段覆盖,具体使用哪份配置,是根据EGG_SERVER_ENV这个环境变量的值。

2、扩展内置对象

内置对象可以被方便地获取到,不过功能有限,我们可以通过egg.js的扩展(Extend)功能去进一步加强、定制框架的能力。

egg.js中有非常多新鲜的特性:“扩展”、“插件”、“多环境配置”,这些特性名称虽然不一样,但本质都是一样的:有则覆盖,无则增加。类似于lodash中的defaults函数,也类似于继承。

因此,如果我们想扩展Application对象,根据egg.js规范,应该在projectDir/app/extend/下增加application.js:

// app/extend/application.js
module.exports = {
  specialName: 'hj's app'
}

以后就可以方便地调用app.specialName获取这个值。

3、扩展应用:插件

Extend特性可以扩展上层框架的内置对象,而插件则可以扩展除router和controller之外的整个app。插件拥有自己的package.json,因此可以独立发布到npm,每个人都可以install,享用你的扩展。

4、定制自己的框架

定制自己的框架可以确定项目的技术选型、减少项目初期的工作,定制框架的思想其实和扩展内置对象、开插件是一样的,但是前置工作会比较多一些。

这些前置工作比较重复、有固定格式,没有必要自己写,建议用骨架搭建:

$ npm install egg-init -g
$ egg-init --type=framework myegg
$ cd myegg

5、Loader加载顺序

当我们基于自己定制的框架framework1,并且在应用中依赖了插件plugin2、plugin3,开发了一个应用:

其中framework1直接基于egg并且内置了plugin1,此时整个app的加载顺序是怎样的呢?加载原则总结一句话是:从被依赖到依赖。

先来分析一下,谁被依赖,谁依赖:

  • 插件可能被其他插件、框架和应用依赖
  • 框架可能被上层框架和应用依赖
  • 应用不被依赖

插件处于被依赖队列的最前方,框架其次,应用最后,因此先加载顺序如图所示,那么我们刚刚的例子,加载顺序应该是:

6、多进程模型

为了最大程度利用多核、增强Node进程健壮性,一般我们会使用PM2一类的工具,如果使用egg.js,就完全不需要担心了,egg利用cluster模块(了解cluster原理请看这篇文章)已经创建了一个非常稳定的多进程模型。

使用egg-bin命令启动时,会启动一个Master进程,Master进程会先fork一个Agent,再根据核数启动对应数量的Worker。Master会监听端口,将请求转发给相应Worker处理,当Worker出错时Master重新fork一个Worker保证服务器健壮性。

Agent是一个特殊的Worker,不做具体的业务逻辑,只负责调度Worker,比如哪个Worker执行定时任务。Agent与Worker的通行时通过Master转发,也就是每个人只知道Master,而不能互相通信,两个Worker之间也需要通过Master转发消息。

总结:

  • Master只负责Worker的初始化、重启、转发IPC消息等进程性工作。
  • Agent负责egg中的Worker调度。
  • Worker负责执行具体的业务逻辑。

延伸阅读1:node.js后台框架有哪些

  • Koa:一个开源的Node web框架,用Generator来实现中间件的流程控制,用try/catch来增强异常处理;
  • Nest:一个用于构建高效、可扩展的Node服务器端应用程序的框架;
  • Socket:是用来在客户端和服务器端之间创建实时双向通信的框架;
  • Sails:是一个非常稳固的Node框架,提供建立任何规模的Web应用所需要的所有功能。