配置提供者
一些配置文件(如 config/hash.ts
)并不以纯对象的形式导出配置。相反,它们导出一个配置提供者。配置提供者为包提供了一个透明的API,以便在应用程序启动后延迟计算配置。
不使用配置提供者
为了理解配置提供者,让我们看看如果不使用配置提供者,config/hash.ts
文件会是什么样子。
import { Scrypt } from '@adonisjs/core/hash/drivers/scrypt'
export default {
default: 'scrypt',
list: {
scrypt: () => new Scrypt({
cost: 16384,
blockSize: 8,
parallelization: 1,
maxMemory: 33554432,
})
}
}
到目前为止,一切都好。我们不是从 drivers
集合中引用 scrypt
驱动程序,而是直接导入它,并使用工厂函数返回一个实例。
假设 Scrypt
驱动程序需要一个 Emitter 类的实例,以便在每次对值进行哈希处理时发出一个事件。
import { Scrypt } from '@adonisjs/core/hash/drivers/scrypt'
import emitter from '@adonisjs/core/services/emitter'
export default {
default: 'scrypt',
list: {
scrypt: () => new Scrypt({
cost: 16384,
blockSize: 8,
parallelization: 1,
maxMemory: 33554432,
}, emitter)
}
}
🚨 上述示例将失败,因为在应用程序启动之前,AdonisJS 容器服务 是不可用的,而配置文件是在应用程序启动阶段之前导入的。
这是AdonisJS架构的一个问题吗?🤷🏻♂️
其实不是。让我们不使用容器服务,而是在配置文件中直接创建一个 Emitter 类的实例。
import { Scrypt } from '@adonisjs/core/hash/drivers/scrypt'
import emitter from '@adonisjs/core/services/emitter'
import { Emitter } from '@adonisjs/core/events'
const emitter = new Emitter()
export default {
default: 'scrypt',
list: {
scrypt: () => new Scrypt({
cost: 16384,
blockSize: 8,
parallelization: 1,
maxMemory: 33554432,
}, emitter)
}
}
现在,我们遇到了一个新问题。我们为 Scrypt
驱动程序创建的 emitter
实例并不是全局可用的,因此我们无法导入它并监听驱动程序发出的事件。
因此,你可能希望将 Emitter
类的构造移动到其自己的文件中,并导出一个实例。这样,你可以将 emitter 实例传递给驱动程序,并使用它来监听事件。
import { Emitter } from '@adonisjs/core/events'
export const emitter = new Emitter()
import { Scrypt } from '@adonisjs/core/hash/drivers/scrypt'
import { Emitter } from '@adonisjs/core/events'
import { emitter } from '#start/emitter'
const emitter = new Emitter()
export default {
default: 'scrypt',
list: {
scrypt: () => new Scrypt({
cost: 16384,
blockSize: 8,
parallelization: 1,
maxMemory: 33554432,
}, emitter)
}
}
上述代码可以正常工作。然而,这次你是手动构造应用程序所需的依赖项。因此,你的应用程序将需要大量的样板代码来将所有内容连接在一起。
在 AdonisJS 中,我们力求编写最少的样板代码,并使用 IoC 容器来查找依赖项。
使用配置提供者
现在,让我们重新编写 config/hash.ts
文件,这次使用配置提供者。配置提供者是一个函数的时髦名称,该函数接受一个 Application 类的实例,并使用容器解析其依赖项。
import { configProvider } from '@adonisjs/core'
import { Scrypt } from '@adonisjs/core/hash/drivers/scrypt'
export default {
default: 'scrypt',
list: {
scrypt: configProvider.create(async (app) => {
const emitter = await app.container.make('emitter')
return () => new Scrypt({
cost: 16384,
blockSize: 8,
parallelization: 1,
maxMemory: 33554432,
}, emitter)
})
}
}
一旦你使用 hash 服务,scrypt
驱动程序的配置提供者将被执行以解析其依赖项。因此,在我们代码的其他地方使用哈希服务之前,我们不会尝试查找 emitter
。
由于配置提供者是异步的,你可能希望通过动态导入来延迟导入 Scrypt
驱动程序。
import { configProvider } from '@adonisjs/core'
import { Scrypt } from '@adonisjs/core/hash/drivers/scrypt'
export default {
default: 'scrypt',
list: {
scrypt: configProvider.create(async (app) => {
const { Scrypt } = await import('@adonisjs/core/hash/drivers/scrypt')
const emitter = await app.container.make('emitter')
return () => new Scrypt({
cost: 16384,
blockSize: 8,
parallelization: 1,
maxMemory: 33554432,
}, emitter)
})
}
}
如何访问已解析的配置?
你可以直接从服务中访问已解析的配置。例如,在哈希服务的情况下,你可以按如下方式获取对已解析配置的引用。
import hash from '@adonisjs/core/services/hash'
console.log(hash.config)