Adapter / 适配器

Adapter 是用来解决一类功能的多种实现,这些实现提供一套相同的接口,类似设计模式里的工厂模式。如:支持多种数据库,支持多种模版引擎等。通过这种方式,可以很方便的在不同的类型中进行切换。Adapter 一般配合 Extend 一起使用。

框架默认提供了很多种 Adapter,如: View、Model、Cache、Session、Websocket,项目中也可以根据需要进行扩展,也可以引入第三方的 Adapter。

Adapter 配置

Adapter 的配置文件为 src/config/adapter.js(多模块项目文件为 src/common/config/adapter.js),格式如下:

  1. const nunjucks = require('think-view-nunjucks');
  2. const ejs = require('think-view-ejs');
  3. const path = require('path');
  4. exports.view = {
  5. type: 'nunjucks', // 默认的模板引擎为 nunjucks
  6. common: { //通用配置
  7. viewPath: path.join(think.ROOT_PATH, 'view'),
  8. sep: '_',
  9. extname: '.html'
  10. },
  11. nunjucks: { // nunjucks 的具体配置
  12. handle: nunjucks
  13. },
  14. ejs: { // ejs 的具体配置
  15. handle: ejs,
  16. viewPath: path.join(think.ROOT_PATH, 'view/ejs/'),
  17. }
  18. }
  19. exports.cache = {
  20. ...
  21. }
  • type 默认使用 Adapter 的类型,具体调用时可以传递参数改写
  • common 配置通用的一些参数,项目启动时会跟具体的 adapter 参数作合并
  • nunjucks ejs 配置特定类型的 Adapter 参数,最终获取到的参数是 common 参数与该参数进行合并
  • handle 对应类型的处理函数,一般为一个类
    Adapter 配置支持运行环境,可以根据不同的运行环境设置不同的配置,如:在开发环境和生产环境的数据库一般都是不一样的,这时候可以通过 adapter.development.jsadapter.production.js 存放有差异的配置,系统启动后会读取对应的运行环境配置和默认配置进行合并。

如:现在是在生产环境下,那么会读取 adapter.production.jsadapter.js 配置进行合并生成最终的 adapter 配置。

Adapter 的配置读取和合并在项目启动时就已经执行,对于上面的配置,最终合并的配置如下:

  1. exports.view = {
  2. type: 'nunjucks', // 默认的模板引擎为 nunjucks
  3. nunjucks: { // nunjucks 的具体配置
  4. handle: nunjucks,
  5. viewPath: path.join(think.ROOT_PATH, 'view'),
  6. sep: '_',
  7. extname: '.html'
  8. },
  9. ejs: { // ejs 的具体配置
  10. handle: ejs,
  11. viewPath: path.join(think.ROOT_PATH, 'view/ejs/'),
  12. viewPath: path.join(think.ROOT_PATH, 'view'),
  13. sep: '_',
  14. extname: '.html'
  15. }
  16. }

可以看到,common 里的配置会被合并到 nunjucks 和 ejs 中,后续再获取的时候就不用再合并 common 里的配置了。

Adapter 配置解析

Adapter 配置存储了所有类型下的详细配置,具体使用时需要对其解析,选择对应的一种进行使用。比如上面的配置文件中,配置了 nunjucks 和 ejs 二种模板引擎的详细配置,但具体使用时一种场景下肯定只会用其一种模板引擎。

Adapter 的配置解析是通过 think-helper 模块中的 parseAdapterConfig 方法来完成的,如:

  1. const helper = require('think-helper');
  2. const viewConfig = think.config('view'); // 获取 view adapter 的详细配置
  3. const nunjucks = helper.parseAdatperConfig(viewConfig); // 获取 nunjucks 的配置,默认 type 为 nunjucks
  4. /**
  5. {
  6. type: 'nunjucks',
  7. handle: nunjucks,
  8. viewPath: path.join(think.ROOT_PATH, 'view'),
  9. sep: '_',
  10. extname: '.html'
  11. }
  12. */
  13. const ejs = helper.parseAdatperConfig(viewConfig, 'ejs') // 获取 ejs 的配置
  14. /**
  15. {
  16. handle: ejs,
  17. type: 'ejs',
  18. viewPath: path.join(think.ROOT_PATH, 'view/ejs/'),
  19. viewPath: path.join(think.ROOT_PATH, 'view'),
  20. sep: '_',
  21. extname: '.html'
  22. }
  23. */

通过 parseAdapterConfig 方法就可以拿到对应类型的配置,然后就可以调用对应的 handle,传入配置然后执行了。

当然,配置解析并不需要使用者在项目中具体调用,一般都是在插件对应的方法里已经处理。

Adapter 使用

Adapter 都是一类功能的不同实现,一般是不能独立使用的,而是配合对应的扩展一起使用。如:view Adapter(think-view-nunjucks、think-view-ejs)配合 think-view 扩展进行使用。

项目安装 think-view 扩展后,提供了对应的方法来渲染模板,但渲染不同的模板需要的模板引擎有对应的 Adapter 来实现,也就是配置中的 handle 字段。

项目中创建 Adapter

除了引入外部的 Adapter 外,项目内也可以创建 Adapter 来使用。Adapter 文件放在 src/adapter/ 目录下(多模块项目放在 src/common/adapter/),如:src/adapter/cache/xcache.js,表示加了一个名为 xcache 的 cache Adapter 类型,然后该文件实现 cache 类型一样的接口即可。

实现完成后,就可以直接通过字符串引用这个 Adapter 了,如:

  1. exports.cache = {
  2. type: 'file',
  3. xcache: {
  4. handle: 'xcache', //这里配置字符串,项目启动时会自动查找 src/adapter/cache/xcache.js 文件
  5. ...
  6. }
  7. }

推荐的 Adapter

框架推荐的 Adapter 为 https://github.com/thinkjs/think-awesome#adapters

原文: https://thinkjs.org/zh-cn/doc/3.0/adapter.html