闭包利用词法作用域实现租户配置隔离,核心是通过工厂函数为不同租户生成独立的插件实例,确保私有配置和缓存结果互不干扰,所有方法自动绑定上下文,模块系统导出工厂函数而非实例。
闭包并非直接“捕获”变量,而是保留对定义时词法作用域的引用。实现多租户配置隔离的核心,在于利用闭包为每个租户创建独立作用域,从而让插件实例之间互不共享状态。
不要导出全局单例,而是导出工厂函数。该函数接收租户标识(如 tenantId)和专属配置,返回封装了租户上下文的插件对象:
function createTenantPlugin(tenantId, config) { // 配置被闭包私有持有,其他租户无法访问 const privateConfig = { ...config, tenantId }; return { getName() { return privateConfig.name || `tenant-${tenantId}`; }, getApiBase() { return privateConfig.apiBase || `https://${tenantId}.api.example.com`; }, fetchUser(id) { return fetch(`${privateConfig.apiBase}/users/${id}`); } };}// 各自持有不同配置,互不影响const tenantA = createTenantPlugin('acme', { apiBase: 'https://acme.api.co' });const tenantB = createTenantPlugin('beta', { apiBase: 'https://beta.api.co' });console.log(tenantA.getApiBase()); // https://acme.api.coconsole.log(tenantB.getApiBase()); // https://beta.api.co
若租户配置需异步获取(例如从后端拉取),可在工厂中封装一次性加载逻辑,并利用闭包缓存结果,避免重复请求:
async function createTenantPlugin(tenantId) { let cachedConfig = null; async function loadConfig() { if (cachedConfig) return cachedConfig; const res = await fetch(`/api/tenants/${tenantId}/config`); cachedConfig = await res.json(); return cachedConfig; } return { async getConfig() { return loadConfig(); // 每个实例维护自己的 cachedConfig }, async fetchWithTenant(path) { const cfg = await loadConfig(); return fetch(`${cfg.apiBase}${path}`); } };}
所有公开方法都应隐式绑定当前租户环境,避免用户手动传参出错。可通过闭包绑定或私有字段统一管理:
tenantId —— 这破坏封装,也易出错。const securedPlugin = withAuth(pluginInstance, authOptions)。即使用了闭包,也要注意模块导出方式:
export default createTenantPlugin。module.exports 返回的是函数而非已执行实例。遵循这些原则,利用闭包构建的多租户插件就能实现可靠的配置隔离,而非依赖变量名或注释的“约定”。