從egg.js從新認識node後端開發

前言

node的後端的開發接觸至今也不過4個月,在最近的開發中選用了以前沒有接觸過的egg.js。雖然尚未深刻開發,可是在與以前的項目的node端比較後仍是有了比較多的感想。java

node後臺開發實戰

以前的項目的主要選型是koa2+sequelize,主要項目結構彷佛也是有板有眼,view層模版渲染,router層負責使用控制器,處理參數,控制器層調用sequelize或者做出數據處理,model層則是數據表的實例。node

開發中的問題spring

  1. 控制器層的解耦和抽象,這部分在以前的開發中是有一點問題的。緣由就是沒有面向對象,而是把控制器直接寫成了一些函數的module,這樣的問題就是很難繼承抽象,控制器的一個方法對應了router層的一個api,很是耦合。
  2. 在api的層的參數校驗沒有作,這層的參數校驗其實頗有必要,能夠更早的把問題直接在這層拋出
  3. 沒有考慮事務,這部分其實也和以前開發的系統較爲簡單有關。

egg.js實戰

在這次新項目的選型中首要就是解決面向對象的問題,雖然也看了一些別人的項目,可是在把控制器寫成一個單例仍是把控制器的函數乾脆做爲靜態函數來用的疑惑時,我參考瞭如下egg.js。以後我發現node後臺開發徹底能夠和java後臺開發同樣有出色的架構。後端

控制反轉和依賴注入

相信這兩種設計思想不少人都會了解,而egg.js中一樣有這兩種思想的實戰。這邊只舉一個例子就能夠清楚的發現api

//app/controller/post.js
const Controller = require('../core/base_controller');
class PostController extends Controller {
  async list() {
    const posts = await this.service.listByUser(this.user);
    this.success(posts);
  }
}

在控制器中並不須要去實例化須要的service,而是能夠直接經過自身的sevice屬性就能夠拿到須要的實例。整個egg其實就是一個容器,類的實例化和依賴管理就是egg的任務了。這一部分的處理其實和spring是很是接近。架構

另外不得不提的一點是,egg在對controller和service的實例化處理是並不不一樣的,egg並不會在一開始就把全部的service實例化,而是採用了即用即插的方式。那麼在實際項目中就須要把更多的業務邏輯抽象到service,而且就須要把能夠分離的服務拆分好。app

egg.js依賴注入的實現

controller的基類koa

class BaseContextClass {
  constructor(ctx) {
    this.ctx = ctx;
    this.app = ctx.app;
    this.config = ctx.app.config;
    this.service = ctx.service;
  }
}

以後就是ctx.service的由來async

// define ctx.service
    Object.defineProperty(app.context, property, {
      get() {
        // distinguish property cache,
        // cache's lifecycle is the same with this context instance
        // e.x. ctx.service1 and ctx.service2 have different cache
        if (!this[CLASSLOADER]) {
          this[CLASSLOADER] = new Map();
        }
        const classLoader = this[CLASSLOADER];

        let instance = classLoader.get(property);
        if (!instance) {
          instance = getInstance(target, this);
          classLoader.set(property, instance);
        }
        return instance;
      },
    });

這段簡短的代碼加註釋很容易就發現service如何實現的即用即插。至於service的loader其實也很容易就不上源碼了,大概就是加載了服務的信息和路徑。而controller的loader則是在初始化的時候就加載控制器。
服務和控制器的實例化的代碼分佈式

function getInstance(values, ctx) {
  // it's a directory when it has no exports
  // then use ClassLoader
  const Class = values[EXPORTS] ? values : null;
  let instance;
  if (Class) {
    if (is.class(Class)) {
      instance = new Class(ctx);
    } else {
      // it's just an object
      instance = Class;
    }
  // Can't set property to primitive, so check again
  // e.x. module.exports = 1;
  } else if (is.primitive(values)) {
    instance = values;
  } else {
    instance = new ClassLoader({ ctx, properties: values });
  }
  return instance;
}

以上就是egg實現依賴注入的原理。

最後

在詢問了作Java後臺的同窗後瞭解到service在不少時候回分佈式的部署,而且最佳實踐就是與上層的控制器和下層的model層實現徹底解耦。總的來講eggjs的學習對從此在代碼解耦的實踐中會有很大的啓發,而且能夠借這個機會從新認識node的後端開發。

以後會接着去學習egg.js的另外一大特點——插件。

相關文章
相關標籤/搜索