From 835059c44c1a29f30cb522a8cc5d3b69276e24b4 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Thu, 17 Feb 2022 16:28:25 +0000
Subject: [PATCH] (ABI change) Rewrite `ComponentStorage`: order extensions by
 property `priority`. Remove `builtinImplementations` and contribute them at
 the first initialization phase instead.

Close #1888, fix #1860.

Add `ComponentStorageInternal` for frontend to provide components.

Deprecate:
- SingletonExtension
- SingletonExtensionPoint
- AbstractSingletonExtensionPoint
- SingletonExtensionSelector
- CommandCallInterceptorProviderImpl
- CommandCallInterceptorProviderImplLazy
- CommandCallParserProviderImpl
- CommandCallParserProviderImplLazy
- CommandCallResolverProviderImpl
- CommandCallResolverProviderImplLazy

ABI breaking change:
- `PermissionServiceProvider`: supertype changed
- `CommandCallResolverProvider.ExtensionPoint`: supertype changed
- `PermissionServiceProvider.ExtensionPoint`: supertype changed
---
 .../backend/mirai-console/src/MiraiConsole.kt |   9 +-
 .../src/MiraiConsoleImplementation.kt         |   6 +-
 .../src/command/BuiltInCommands.kt            |   3 +-
 .../src/command/parse/CommandCallParser.kt    |   8 +-
 .../parse/SpaceSeparatedCommandCallParser.kt  |  12 +-
 .../resolve/BuiltInCommandCallResolver.kt     |   8 +-
 .../command/resolve/CommandCallInterceptor.kt |  48 ++--
 .../command/resolve/CommandCallResolver.kt    |  10 +-
 .../src/extension/ComponentStorage.kt         |  92 ++++++-
 .../mirai-console/src/extension/Extension.kt  |  20 +-
 .../src/extension/ExtensionPoint.kt           |  68 ++++--
 .../src/extension/ExtensionRegistry.kt        |  46 ++++
 .../CommandCallInterceptorProvider.kt         |   8 +-
 .../extensions/CommandCallParserProvider.kt   |  15 +-
 .../extensions/CommandCallResolverProvider.kt |  21 +-
 .../extensions/PermissionServiceProvider.kt   |  44 +---
 .../src/extensions/PluginLoaderProvider.kt    |   7 +-
 .../extensions/SingletonExtensionSelector.kt  |  42 +++-
 .../MiraiConsoleImplementationBridge.kt       |  47 ++--
 .../extension/ComponentStorageInternal.kt     | 226 ++++++++----------
 .../SingletonExtensionSelectorImpl.kt         |   9 +-
 .../permission/BuiltInPermissionServices.kt   |   9 +-
 .../src/internal/plugin/PluginManagerImpl.kt  |  12 +-
 .../src/permission/PermissionService.kt       |  16 +-
 .../extension/GlobalComponentStorageTest.kt   |  80 +++++++
 25 files changed, 554 insertions(+), 312 deletions(-)
 create mode 100644 mirai-console/backend/mirai-console/src/extension/ExtensionRegistry.kt
 create mode 100644 mirai-console/backend/mirai-console/test/extension/GlobalComponentStorageTest.kt

diff --git a/mirai-console/backend/mirai-console/src/MiraiConsole.kt b/mirai-console/backend/mirai-console/src/MiraiConsole.kt
index 5dae7a875..c20cf511f 100644
--- a/mirai-console/backend/mirai-console/src/MiraiConsole.kt
+++ b/mirai-console/backend/mirai-console/src/MiraiConsole.kt
@@ -162,7 +162,7 @@ public interface MiraiConsole : CoroutineScope {
          *
          * 调用 [Bot.login] 可登录.
          *
-         * @see Bot.botInstances 获取现有 [Bot] 实例列表
+         * @see Bot.instances 获取现有 [Bot] 实例列表
          * @see BotConfigurationAlterer ExtensionPoint
          */
         // don't static
@@ -225,11 +225,8 @@ public interface MiraiConsole : CoroutineScope {
                 configuration()
             }
 
-            config = GlobalComponentStorage.run {
-                BotConfigurationAlterer.foldExtensions(config) { acc, extension ->
-                    extension.alterConfiguration(id, acc)
-
-                }
+            config = GlobalComponentStorage.foldExtensions(BotConfigurationAlterer, config) { acc, extension ->
+                extension.alterConfiguration(id, acc)
             }
 
             return when (password) {
diff --git a/mirai-console/backend/mirai-console/src/MiraiConsoleImplementation.kt b/mirai-console/backend/mirai-console/src/MiraiConsoleImplementation.kt
index 0d7ded158..a5911a72c 100644
--- a/mirai-console/backend/mirai-console/src/MiraiConsoleImplementation.kt
+++ b/mirai-console/backend/mirai-console/src/MiraiConsoleImplementation.kt
@@ -25,7 +25,6 @@ import net.mamoe.mirai.console.extension.ComponentStorage
 import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
 import net.mamoe.mirai.console.internal.command.CommandManagerImpl
 import net.mamoe.mirai.console.internal.data.builtins.ConsoleDataScopeImpl
-import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
 import net.mamoe.mirai.console.internal.logging.LoggerControllerImpl
 import net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl
 import net.mamoe.mirai.console.internal.pluginManagerImpl
@@ -317,6 +316,9 @@ public interface MiraiConsoleImplementation : CoroutineScope {
     @ConsoleFrontEndImplementation
     public interface BackendAccess {
         // GlobalComponentStorage
+        /**
+         * 在 Mirai Console 第一个 phase 之后会包含内建 storages.
+         */
         public val globalComponentStorage: ComponentStorage
 
         // PluginManagerImpl.resolvedPlugins
@@ -365,7 +367,7 @@ public interface MiraiConsoleImplementation : CoroutineScope {
     @ConsoleFrontEndImplementation
     public companion object {
         private val backendAccessInstance = object : BackendAccess {
-            override val globalComponentStorage: ComponentStorage get() = GlobalComponentStorage
+            override val globalComponentStorage: ComponentStorage get() = getBridge().globalComponentStorage
             override val resolvedPlugins: MutableList<Plugin> get() = MiraiConsole.pluginManagerImpl.resolvedPlugins
         }
 
diff --git a/mirai-console/backend/mirai-console/src/command/BuiltInCommands.kt b/mirai-console/backend/mirai-console/src/command/BuiltInCommands.kt
index 74fe12dbf..4b24c829c 100644
--- a/mirai-console/backend/mirai-console/src/command/BuiltInCommands.kt
+++ b/mirai-console/backend/mirai-console/src/command/BuiltInCommands.kt
@@ -28,6 +28,7 @@ import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig
 import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.*
 import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.PasswordKind.MD5
 import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.PasswordKind.PLAIN
+import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
 import net.mamoe.mirai.console.internal.permission.BuiltInPermissionService
 import net.mamoe.mirai.console.internal.pluginManagerImpl
 import net.mamoe.mirai.console.internal.util.autoHexToBytes
@@ -484,7 +485,7 @@ public object BuiltInCommands {
                         lightYellow()
                         "Built In Permission Service"
                     } else {
-                        val plugin = PermissionServiceProvider.providerPlugin
+                        val plugin = GlobalComponentStorage.getPreferredExtension(PermissionServiceProvider).plugin
                         if (plugin == null) {
                             PermissionService.INSTANCE.toString()
                         } else {
diff --git a/mirai-console/backend/mirai-console/src/command/parse/CommandCallParser.kt b/mirai-console/backend/mirai-console/src/command/parse/CommandCallParser.kt
index 8a8f76b25..b7862a233 100644
--- a/mirai-console/backend/mirai-console/src/command/parse/CommandCallParser.kt
+++ b/mirai-console/backend/mirai-console/src/command/parse/CommandCallParser.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -44,10 +44,8 @@ public interface CommandCallParser {
          */
         @JvmStatic
         public fun MessageChain.parseCommandCall(sender: CommandSender): CommandCall? {
-            GlobalComponentStorage.run {
-                CommandCallParserProvider.useExtensions { provider ->
-                    provider.instance.parse(sender, this@parseCommandCall)?.let { return it }
-                }
+            GlobalComponentStorage.useEachExtensions(CommandCallParserProvider) { provider ->
+                provider.instance.parse(sender, this@parseCommandCall)?.let { return it }
             }
             return null
         }
diff --git a/mirai-console/backend/mirai-console/src/command/parse/SpaceSeparatedCommandCallParser.kt b/mirai-console/backend/mirai-console/src/command/parse/SpaceSeparatedCommandCallParser.kt
index 68648b849..f2496d635 100644
--- a/mirai-console/backend/mirai-console/src/command/parse/SpaceSeparatedCommandCallParser.kt
+++ b/mirai-console/backend/mirai-console/src/command/parse/SpaceSeparatedCommandCallParser.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -12,7 +12,6 @@ package net.mamoe.mirai.console.command.parse
 import net.mamoe.mirai.console.command.CommandSender
 import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
 import net.mamoe.mirai.console.extensions.CommandCallParserProvider
-import net.mamoe.mirai.console.extensions.CommandCallParserProviderImpl
 import net.mamoe.mirai.console.internal.command.flattenCommandComponents
 import net.mamoe.mirai.console.util.ConsoleExperimentalApi
 import net.mamoe.mirai.message.data.MessageChain
@@ -22,6 +21,13 @@ import net.mamoe.mirai.message.data.content
 @ConsoleExperimentalApi
 @ExperimentalCommandDescriptors
 public object SpaceSeparatedCommandCallParser : CommandCallParser {
+
+    @ConsoleExperimentalApi
+    @ExperimentalCommandDescriptors
+    public object Provider : CommandCallParserProvider {
+        override val instance: CommandCallParser get() = SpaceSeparatedCommandCallParser
+    }
+
     override fun parse(caller: CommandSender, message: MessageChain): CommandCall? {
         val flatten = message.flattenCommandComponents().filterIsInstance<MessageContent>()
         if (flatten.isEmpty()) return null
@@ -31,6 +37,4 @@ public object SpaceSeparatedCommandCallParser : CommandCallParser {
             valueArguments = flatten.drop(1).map(::DefaultCommandValueArgument)
         )
     }
-
-    public object Provider : CommandCallParserProvider by CommandCallParserProviderImpl(SpaceSeparatedCommandCallParser)
 }
\ No newline at end of file
diff --git a/mirai-console/backend/mirai-console/src/command/resolve/BuiltInCommandCallResolver.kt b/mirai-console/backend/mirai-console/src/command/resolve/BuiltInCommandCallResolver.kt
index 12378024d..898888204 100644
--- a/mirai-console/backend/mirai-console/src/command/resolve/BuiltInCommandCallResolver.kt
+++ b/mirai-console/backend/mirai-console/src/command/resolve/BuiltInCommandCallResolver.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -15,6 +15,7 @@ import net.mamoe.mirai.console.command.descriptor.ArgumentAcceptance.Companion.i
 import net.mamoe.mirai.console.command.parse.CommandCall
 import net.mamoe.mirai.console.command.parse.CommandValueArgument
 import net.mamoe.mirai.console.command.parse.DefaultCommandValueArgument
+import net.mamoe.mirai.console.extensions.CommandCallResolverProvider
 import net.mamoe.mirai.console.internal.data.classifierAsKClass
 import net.mamoe.mirai.console.util.ConsoleExperimentalApi
 import net.mamoe.mirai.console.util.safeCast
@@ -27,6 +28,11 @@ import net.mamoe.mirai.message.data.toMessageChain
 @ConsoleExperimentalApi
 @ExperimentalCommandDescriptors
 public object BuiltInCommandCallResolver : CommandCallResolver {
+
+    internal object Provider : CommandCallResolverProvider {
+        override val instance: CommandCallResolver = BuiltInCommandCallResolver
+    }
+
     override fun resolve(call: CommandCall): CommandResolveResult {
         val callee = CommandManager.matchCommand(call.calleeName)
             ?: return CommandResolveResult(CommandExecuteResult.UnresolvedCommand(call))
diff --git a/mirai-console/backend/mirai-console/src/command/resolve/CommandCallInterceptor.kt b/mirai-console/backend/mirai-console/src/command/resolve/CommandCallInterceptor.kt
index bf7529bd3..845e3503d 100644
--- a/mirai-console/backend/mirai-console/src/command/resolve/CommandCallInterceptor.kt
+++ b/mirai-console/backend/mirai-console/src/command/resolve/CommandCallInterceptor.kt
@@ -66,15 +66,13 @@ public interface CommandCallInterceptor {
          */
         @JvmStatic
         public fun Message.intercepted(caller: CommandSender): InterceptResult<Message> {
-            GlobalComponentStorage.run {
-                return CommandCallInterceptorProvider.foldExtensions(this@intercepted) { acc, ext ->
-                    val intercepted = ext.instance.interceptBeforeCall(acc, caller)
-                    intercepted?.fold(
-                        onIntercepted = { return intercepted },
-                        otherwise = { it }
-                    ) ?: acc
-                }.let { InterceptResult(it) }
-            }
+            return GlobalComponentStorage.foldExtensions(CommandCallInterceptorProvider, this@intercepted) { acc, ext ->
+                val intercepted = ext.instance.interceptBeforeCall(acc, caller)
+                intercepted?.fold(
+                    onIntercepted = { return intercepted },
+                    otherwise = { it }
+                ) ?: acc
+            }.let { InterceptResult(it) }
         }
 
         /**
@@ -83,15 +81,13 @@ public interface CommandCallInterceptor {
          */
         @JvmStatic
         public fun CommandCall.intercepted(): InterceptResult<CommandCall> {
-            GlobalComponentStorage.run {
-                return CommandCallInterceptorProvider.foldExtensions(this@intercepted) { acc, ext ->
-                    val intercepted = ext.instance.interceptCall(acc)
-                    intercepted?.fold(
-                        onIntercepted = { return intercepted },
-                        otherwise = { it }
-                    ) ?: acc
-                }.let { InterceptResult(it) }
-            }
+            return GlobalComponentStorage.foldExtensions(CommandCallInterceptorProvider, this@intercepted) { acc, ext ->
+                val intercepted = ext.instance.interceptCall(acc)
+                intercepted?.fold(
+                    onIntercepted = { return intercepted },
+                    otherwise = { it }
+                ) ?: acc
+            }.let { InterceptResult(it) }
         }
 
         /**
@@ -100,15 +96,13 @@ public interface CommandCallInterceptor {
          */
         @JvmStatic
         public fun ResolvedCommandCall.intercepted(): InterceptResult<ResolvedCommandCall> {
-            GlobalComponentStorage.run {
-                return CommandCallInterceptorProvider.foldExtensions(this@intercepted) { acc, ext ->
-                    val intercepted = ext.instance.interceptResolvedCall(acc)
-                    intercepted?.fold(
-                        onIntercepted = { return intercepted },
-                        otherwise = { it }
-                    ) ?: acc
-                }.let { InterceptResult(it) }
-            }
+            return GlobalComponentStorage.foldExtensions(CommandCallInterceptorProvider, this@intercepted) { acc, ext ->
+                val intercepted = ext.instance.interceptResolvedCall(acc)
+                intercepted?.fold(
+                    onIntercepted = { return intercepted },
+                    otherwise = { it }
+                ) ?: acc
+            }.let { InterceptResult(it) }
         }
     }
 }
diff --git a/mirai-console/backend/mirai-console/src/command/resolve/CommandCallResolver.kt b/mirai-console/backend/mirai-console/src/command/resolve/CommandCallResolver.kt
index 6788e31fd..86465fc53 100644
--- a/mirai-console/backend/mirai-console/src/command/resolve/CommandCallResolver.kt
+++ b/mirai-console/backend/mirai-console/src/command/resolve/CommandCallResolver.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -76,11 +76,9 @@ public interface CommandCallResolver {
         @ConsoleExperimentalApi
         @ExperimentalCommandDescriptors
         public fun CommandCall.resolve(): CommandResolveResult {
-            GlobalComponentStorage.run {
-                val instance =
-                    CommandCallResolverProvider.findSingletonInstance(CommandCallResolverProvider.builtinImplementation)
-                return instance.resolve(this@resolve)
-            }
+            return GlobalComponentStorage.getExtensions(CommandCallResolverProvider).first()
+                .extension.instance
+                .resolve(this@resolve)
         }
     }
 }
\ No newline at end of file
diff --git a/mirai-console/backend/mirai-console/src/extension/ComponentStorage.kt b/mirai-console/backend/mirai-console/src/extension/ComponentStorage.kt
index 27a1abbda..40970eeae 100644
--- a/mirai-console/backend/mirai-console/src/extension/ComponentStorage.kt
+++ b/mirai-console/backend/mirai-console/src/extension/ComponentStorage.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -9,27 +9,99 @@
 
 package net.mamoe.mirai.console.extension
 
+import net.mamoe.mirai.console.ConsoleFrontEndImplementation
+import net.mamoe.mirai.console.MiraiConsoleImplementation
 import net.mamoe.mirai.console.plugin.Plugin
 import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
 import net.mamoe.mirai.console.plugin.jvm.JvmPlugin.Companion.onLoad
+import net.mamoe.mirai.utils.MiraiExperimentalApi
+import java.util.stream.Stream
 
 /**
  * 组件容器, 容纳 [Plugin] 注册的 [Extension].
  *
+ * 插件可在 [JvmPlugin.onLoad] 时提供扩展. 前端可在 [MiraiConsoleImplementation.BackendAccess.globalComponentStorage] 获取全局组件容器.
+ * 目前未允许获取全局组件容器. 如有需求请 [提交 issues](https://github.com/mamoe/mirai/issues/new/choose).
+ *
+ * 实现细节: 线程安全.
+ *
  * @see Extension
  * @see JvmPlugin.onLoad
  */
 public interface ComponentStorage {
-    public fun <T : Extension> contribute(
-        extensionPoint: ExtensionPoint<T>,
-        plugin: Plugin,
-        extensionInstance: T,
-    )
 
-    public fun <T : Extension> contribute(
-        extensionPoint: ExtensionPoint<T>,
+    /**
+     * 注册一个扩展
+     */
+    public fun <E : Extension> contribute(
+        extensionPoint: ExtensionPoint<E>,
         plugin: Plugin,
-        lazyInstance: () -> T,
-    )
+        extensionInstance: E,
+    ) // 2.11: E changed to T (only naming)
+
+    /**
+     * 注册一个扩展. [lazyInstance] 将会在 [getExtensions] 时才会计算.
+     */
+    public fun <E : Extension> contribute(
+        extensionPoint: ExtensionPoint<E>,
+        plugin: Plugin,
+        lazyInstance: () -> E,
+    ) // 2.11: E changed to T (only naming)
+
+    /**
+     * 获取优先级最高的 [ExtensionPoint] 扩展实例. 在未找到任何注册的实例时抛出 [NoSuchElementException].
+     *
+     * @since 2.11
+     */
+    @MiraiExperimentalApi
+    public fun <E : Extension> getPreferredExtension(
+        extensionPoint: ExtensionPoint<E>,
+    ): ExtensionRegistry<E> {
+        return getExtensions(extensionPoint).firstOrNull()
+            ?: throw NoSuchElementException("No extension registered for $extensionPoint")
+    }
+
+    /**
+     * 获取注册的 [ExtensionPoint] 扩展实例列表. 返回的 [Sequence] 以 [Extension.priority] 倒序排序.
+     *
+     * @since 2.11
+     */
+    public fun <E : Extension> getExtensions(
+        extensionPoint: ExtensionPoint<E>,
+    ): Sequence<ExtensionRegistry<E>>
+
+    /**
+     * 获取注册的 [ExtensionPoint] 扩展实例列表. 返回的 [Stream] 以 [Extension.priority] 倒序排序.
+     *
+     * @since 2.11
+     */
+    public fun <E : Extension> getExtensionsStream(
+        extensionPoint: ExtensionPoint<E>,
+    ): Stream<ExtensionRegistry<E>>
 }
 
+/**
+ * 仅前端实现可用
+ */
+@ConsoleFrontEndImplementation
+public interface ComponentStorageInternal : ComponentStorage {
+
+    /**
+     * 注册一个由 Mirai Console 实现的扩展 (因此没有相关 [Plugin]). [lazyInstance] 将会在 [getExtensions] 时才会计算.
+     */
+    public fun <E : Extension> contributeConsole(
+        extensionPoint: ExtensionPoint<E>,
+        lazyInstance: () -> E,
+    )
+
+    /**
+     * 注册一个由 Mirai Console 实现的扩展 (因此没有相关 [Plugin]).
+     */
+    public fun <E : Extension> contributeConsole(
+        extensionPoint: ExtensionPoint<E>,
+        instance: E,
+    ) {
+        @Suppress("USELESS_CAST") // bug
+        contributeConsole(extensionPoint, { instance } as () -> E)
+    }
+}
diff --git a/mirai-console/backend/mirai-console/src/extension/Extension.kt b/mirai-console/backend/mirai-console/src/extension/Extension.kt
index 34a4d9d81..fc5721fa0 100644
--- a/mirai-console/backend/mirai-console/src/extension/Extension.kt
+++ b/mirai-console/backend/mirai-console/src/extension/Extension.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -9,12 +9,15 @@
 
 package net.mamoe.mirai.console.extension
 
+import net.mamoe.mirai.console.command.parse.SpaceSeparatedCommandCallParser
 import net.mamoe.mirai.console.extensions.PermissionServiceProvider
 import net.mamoe.mirai.console.extensions.PluginLoaderProvider
 import net.mamoe.mirai.console.extensions.SingletonExtensionSelector
 import net.mamoe.mirai.console.extensions.SingletonExtensionSelector.ExtensionPoint.selectSingleton
 import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
 import net.mamoe.mirai.console.plugin.jvm.JvmPlugin.Companion.onLoad
+import net.mamoe.mirai.console.util.ConsoleExperimentalApi
+import net.mamoe.mirai.utils.DeprecatedSinceMirai
 
 /**
  * 表示一个扩展.
@@ -37,7 +40,18 @@ import net.mamoe.mirai.console.plugin.jvm.JvmPlugin.Companion.onLoad
  *
  * @see ComponentStorage
  */
-public interface Extension
+public interface Extension {
+    /**
+     * 优先级. 越高越先使用. 内嵌的 [SpaceSeparatedCommandCallParser] 拥有优先级 0.
+     *
+     * 若两个 [InstanceExtension] 有相同的优先级, 将会优先使用内嵌的实现, 再按 [ComponentStorage.contribute] 顺序依次使用.
+     *
+     * @since 2.11
+     */ // https://github.com/mamoe/mirai/issues/1860
+    @ConsoleExperimentalApi
+    public val priority: Int
+        get() = 0
+}
 
 /**
  * 增加一些函数 (方法)的扩展
@@ -51,6 +65,8 @@ public interface FunctionExtension : Extension
  *
  * @see PermissionServiceProvider
  */
+@Deprecated("Please use InstanceExtension instead.", replaceWith = ReplaceWith("InstanceExtension"))
+@DeprecatedSinceMirai(warningSince = "2.11")
 public interface SingletonExtension<T> : Extension {
     public val instance: T
 }
diff --git a/mirai-console/backend/mirai-console/src/extension/ExtensionPoint.kt b/mirai-console/backend/mirai-console/src/extension/ExtensionPoint.kt
index f861b92ed..ddd28ac2a 100644
--- a/mirai-console/backend/mirai-console/src/extension/ExtensionPoint.kt
+++ b/mirai-console/backend/mirai-console/src/extension/ExtensionPoint.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -12,13 +12,15 @@
 package net.mamoe.mirai.console.extension
 
 import net.mamoe.mirai.console.extensions.SingletonExtensionSelector
-import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
 import net.mamoe.mirai.console.util.ConsoleExperimentalApi
+import net.mamoe.mirai.utils.DeprecatedSinceMirai
 import kotlin.reflect.KClass
 
 
 /**
- * 由 [Extension] 的伴生对象实现.
+ * 表示一个扩展接入点(扩展类型). 在 Kotlin 由 [Extension] 的伴生对象实现, 在 Java 可通过静态字段提供.
+ *
+ * 在[注册扩展][ComponentStorage.contribute]时需要提供其 [ExtensionPoint], [ExtensionPoint] 也可以用于获取所有注册的扩展 ([ComponentStorage.getExtensions]).
  *
  * @see AbstractExtensionPoint
  */
@@ -37,6 +39,8 @@ public abstract class AbstractExtensionPoint<T : Extension>(
 /**
  * 表示一个 [SingletonExtension] 的 [ExtensionPoint]
  */
+@Deprecated("Please use InstanceExtensionPoint instead.", replaceWith = ReplaceWith("InstanceExtensionPoint"))
+@DeprecatedSinceMirai(warningSince = "2.11")
 public interface SingletonExtensionPoint<T : SingletonExtension<*>> : ExtensionPoint<T>
 
 /**
@@ -55,34 +59,56 @@ public abstract class AbstractInstanceExtensionPoint<E : InstanceExtension<T>, T
  * @since 2.10
  */
 @ConsoleExperimentalApi
-constructor(
-    extensionType: KClass<E>,
-    /**
-     * 内建的实现列表.
-     */
-    @ConsoleExperimentalApi
-    public vararg val builtinImplementations: () -> E,
+public constructor(
+    extensionType: KClass<E>
 ) : AbstractExtensionPoint<E>(extensionType) {
 
     /**
      * @since 2.10
      */
+    @Deprecated(
+        "Default(builtin) implementations are not allowed any more. " +
+                "For plugin authors, provide them with lower priority when plugin being loaded(through the ComponentScope). " +
+                "For frontend implementers, provide them by `BackendAccess.globalComponentScope.contribute`. ",
+        replaceWith = ReplaceWith("AbstractInstanceExtensionPoint(extensionType)"),
+        level = DeprecationLevel.ERROR,
+    )
+    @DeprecatedSinceMirai(errorSince = "2.11") // for removal
     @ConsoleExperimentalApi
-    public constructor(extensionType: KClass<E>) : this(
-        extensionType,
-        builtinImplementations = arrayOf<() -> E>() as Array<out () -> E>
-    ) // to avoid resolution ambiguity
+    public constructor(
+        extensionType: KClass<E>,
+        /**
+         * 内建的实现列表.
+         */
+        builtinImplementations: () -> E,
+    ) : this(extensionType)
 
     /**
      * @since 2.0
      */
-    @ConsoleExperimentalApi
+    @Deprecated(
+        "Default(builtin) implementations are not allowed any more. " +
+                "For plugin authors, provide them with lower priority when plugin being loaded(through the ComponentScope). " +
+                "For frontend implementers, provide them by `BackendAccess.globalComponentScope.contribute`. ",
+        replaceWith = ReplaceWith("AbstractInstanceExtensionPoint(extensionType)"),
+        level = DeprecationLevel.ERROR
+    )
+    @DeprecatedSinceMirai(errorSince = "2.11") // for removal
+    @ConsoleExperimentalApi // was experimental since 2.0
     public constructor(extensionType: KClass<E>, vararg builtinImplementations: E) : this(
         extensionType,
-        builtinImplementations = builtinImplementations.map { { it } }.toTypedArray()
     )
 }
 
+@Deprecated(
+    "Please use AbstractInstanceExtensionPoint instead.",
+    replaceWith = ReplaceWith(
+        "AbstractInstanceExtension",
+        "net.mamoe.mirai.console.extension.AbstractInstanceExtensionPoint"
+    )
+)
+@DeprecatedSinceMirai(warningSince = "2.11")
+@Suppress("DEPRECATION")
 public abstract class AbstractSingletonExtensionPoint<E : SingletonExtension<T>, T>
 /**
  * @since 2.10
@@ -111,12 +137,6 @@ constructor(
      * 由 [SingletonExtensionSelector] 选择后的实例.
      */
     @ConsoleExperimentalApi
-    public open val selectedInstance: T by lazy {
-        GlobalComponentStorage.run {
-            this@AbstractSingletonExtensionPoint.findSingletonInstance(
-                extensionType,
-                builtinImplementation
-            )
-        }
-    }
+    public open val selectedInstance: T
+        get() = throw UnsupportedOperationException("SingletonExtension has been deprecated.")
 }
\ No newline at end of file
diff --git a/mirai-console/backend/mirai-console/src/extension/ExtensionRegistry.kt b/mirai-console/backend/mirai-console/src/extension/ExtensionRegistry.kt
new file mode 100644
index 000000000..c950c292b
--- /dev/null
+++ b/mirai-console/backend/mirai-console/src/extension/ExtensionRegistry.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+package net.mamoe.mirai.console.extension
+
+import net.mamoe.mirai.console.plugin.Plugin
+import net.mamoe.mirai.utils.NotStableForInheritance
+
+/**
+ * 一个已经注册的 [Extension]. 可通过 [ComponentStorage.getExtensions] 获得.
+ *
+ * @since 2.11
+ */
+@NotStableForInheritance
+public interface ExtensionRegistry<E : Extension> {
+    /**
+     * 提供该 [ExtensionRegistry] 的插件. 若为 `null` 则表示由 Mirai Console 内置或者由前端实现.
+     */
+    public val plugin: Plugin?
+
+    /**
+     * [Extension] 实例.
+     */
+    public val extension: E
+}
+
+internal inline val <T> ExtensionRegistry<out InstanceExtension<T>>.instance get() = extension.instance
+
+internal class ExtensionRegistryImpl<E : Extension> internal constructor(
+    /**
+     * 提供该 [ExtensionRegistry] 的插件. 若为 `null` 则表示由 Mirai Console 内置或者由前端实现.
+     */
+    override val plugin: Plugin?,
+    /**
+     * [Extension] 实例.
+     */
+    extensionInitializer: () -> E,
+) : ExtensionRegistry<E> {
+    override val extension: E by lazy(extensionInitializer)
+}
diff --git a/mirai-console/backend/mirai-console/src/extensions/CommandCallInterceptorProvider.kt b/mirai-console/backend/mirai-console/src/extensions/CommandCallInterceptorProvider.kt
index 0b5ffcc74..25dfbc9cd 100644
--- a/mirai-console/backend/mirai-console/src/extensions/CommandCallInterceptorProvider.kt
+++ b/mirai-console/backend/mirai-console/src/extensions/CommandCallInterceptorProvider.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -13,19 +13,25 @@ import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
 import net.mamoe.mirai.console.command.resolve.CommandCallInterceptor
 import net.mamoe.mirai.console.extension.AbstractInstanceExtensionPoint
 import net.mamoe.mirai.console.extension.InstanceExtension
+import net.mamoe.mirai.utils.DeprecatedSinceMirai
 
 @ExperimentalCommandDescriptors
 public interface CommandCallInterceptorProvider : InstanceExtension<CommandCallInterceptor> {
+    @ExperimentalCommandDescriptors
     public companion object ExtensionPoint :
         AbstractInstanceExtensionPoint<CommandCallInterceptorProvider, CommandCallInterceptor>(
             CommandCallInterceptorProvider::class
         )
 }
 
+@Deprecated("Deprecated for removal. Please implement your own CommandCallInterceptorProvider.")
+@DeprecatedSinceMirai(warningSince = "2.11") // for removal.
 @ExperimentalCommandDescriptors
 public class CommandCallInterceptorProviderImpl(override val instance: CommandCallInterceptor) :
     CommandCallInterceptorProvider
 
+@Deprecated("Deprecated for removal. Please implement your own CommandCallInterceptorProvider.")
+@DeprecatedSinceMirai(warningSince = "2.11") // for removal.
 @ExperimentalCommandDescriptors
 public class CommandCallInterceptorProviderImplLazy(initializer: () -> CommandCallInterceptor) :
     CommandCallInterceptorProvider {
diff --git a/mirai-console/backend/mirai-console/src/extensions/CommandCallParserProvider.kt b/mirai-console/backend/mirai-console/src/extensions/CommandCallParserProvider.kt
index 8c8d4ca99..f20075007 100644
--- a/mirai-console/backend/mirai-console/src/extensions/CommandCallParserProvider.kt
+++ b/mirai-console/backend/mirai-console/src/extensions/CommandCallParserProvider.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -11,26 +11,27 @@ package net.mamoe.mirai.console.extensions
 
 import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
 import net.mamoe.mirai.console.command.parse.CommandCallParser
-import net.mamoe.mirai.console.command.parse.SpaceSeparatedCommandCallParser
 import net.mamoe.mirai.console.extension.AbstractInstanceExtensionPoint
 import net.mamoe.mirai.console.extension.InstanceExtension
+import net.mamoe.mirai.utils.DeprecatedSinceMirai
 
 /**
  * The provider of [CommandCallParser]
  */
 @ExperimentalCommandDescriptors
 public interface CommandCallParserProvider : InstanceExtension<CommandCallParser> {
+    @ExperimentalCommandDescriptors
     public companion object ExtensionPoint :
-        AbstractInstanceExtensionPoint<CommandCallParserProvider, CommandCallParser>(
-            CommandCallParserProvider::class,
-            SpaceSeparatedCommandCallParser.Provider
-        )
+        AbstractInstanceExtensionPoint<CommandCallParserProvider, CommandCallParser>(CommandCallParserProvider::class)
 }
 
-
+@Deprecated("Deprecated for removal. Please implement your own CommandCallParserProvider.")
+@DeprecatedSinceMirai(warningSince = "2.11") // for removal.
 @ExperimentalCommandDescriptors
 public class CommandCallParserProviderImpl(override val instance: CommandCallParser) : CommandCallParserProvider
 
+@Deprecated("Deprecated for removal. Please implement your own CommandCallParserProvider.")
+@DeprecatedSinceMirai(warningSince = "2.11") // for removal.
 @ExperimentalCommandDescriptors
 public class CommandCallParserProviderImplLazy(initializer: () -> CommandCallParser) : CommandCallParserProvider {
     override val instance: CommandCallParser by lazy(initializer)
diff --git a/mirai-console/backend/mirai-console/src/extensions/CommandCallResolverProvider.kt b/mirai-console/backend/mirai-console/src/extensions/CommandCallResolverProvider.kt
index 3181a9045..fdbdc9943 100644
--- a/mirai-console/backend/mirai-console/src/extensions/CommandCallResolverProvider.kt
+++ b/mirai-console/backend/mirai-console/src/extensions/CommandCallResolverProvider.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -10,23 +10,26 @@
 package net.mamoe.mirai.console.extensions
 
 import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
-import net.mamoe.mirai.console.command.resolve.BuiltInCommandCallResolver
 import net.mamoe.mirai.console.command.resolve.CommandCallResolver
-import net.mamoe.mirai.console.extension.AbstractSingletonExtensionPoint
-import net.mamoe.mirai.console.extension.SingletonExtension
+import net.mamoe.mirai.console.extension.AbstractInstanceExtensionPoint
+import net.mamoe.mirai.console.extension.InstanceExtension
+import net.mamoe.mirai.utils.DeprecatedSinceMirai
 
 @ExperimentalCommandDescriptors
-public interface CommandCallResolverProvider : SingletonExtension<CommandCallResolver> {
+public interface CommandCallResolverProvider : InstanceExtension<CommandCallResolver> {
+
+    @ExperimentalCommandDescriptors
     public companion object ExtensionPoint :
-        AbstractSingletonExtensionPoint<CommandCallResolverProvider, CommandCallResolver>(
-            CommandCallResolverProvider::class,
-            { BuiltInCommandCallResolver }
-        )
+        AbstractInstanceExtensionPoint<CommandCallResolverProvider, CommandCallResolver>(CommandCallResolverProvider::class)
 }
 
+@Deprecated("Deprecated for removal. Please implement your own CommandCallResolverProvider.")
+@DeprecatedSinceMirai(warningSince = "2.11") // for removal.
 @ExperimentalCommandDescriptors
 public class CommandCallResolverProviderImpl(override val instance: CommandCallResolver) : CommandCallResolverProvider
 
+@Deprecated("Deprecated for removal. Please implement your own CommandCallResolverProvider.")
+@DeprecatedSinceMirai(warningSince = "2.11") // for removal.
 @ExperimentalCommandDescriptors
 public class CommandCallResolverProviderImplLazy(initializer: () -> CommandCallResolver) : CommandCallResolverProvider {
     override val instance: CommandCallResolver by lazy(initializer)
diff --git a/mirai-console/backend/mirai-console/src/extensions/PermissionServiceProvider.kt b/mirai-console/backend/mirai-console/src/extensions/PermissionServiceProvider.kt
index ce2f1ec6e..c880ed105 100644
--- a/mirai-console/backend/mirai-console/src/extensions/PermissionServiceProvider.kt
+++ b/mirai-console/backend/mirai-console/src/extensions/PermissionServiceProvider.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -9,55 +9,35 @@
 
 package net.mamoe.mirai.console.extensions
 
-import net.mamoe.mirai.console.extension.AbstractSingletonExtensionPoint
-import net.mamoe.mirai.console.extension.SingletonExtension
-import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
-import net.mamoe.mirai.console.internal.permission.BuiltInPermissionService
+import net.mamoe.mirai.console.extension.AbstractInstanceExtensionPoint
+import net.mamoe.mirai.console.extension.InstanceExtension
 import net.mamoe.mirai.console.permission.PermissionService
-import net.mamoe.mirai.console.plugin.Plugin
-import net.mamoe.mirai.console.util.ConsoleExperimentalApi
+import net.mamoe.mirai.utils.DeprecatedSinceMirai
 
 /**
  * [权限服务][PermissionService] 提供器.
  *
  * 当插件注册 [PermissionService] 后, 默认会使用插件的 [PermissionService].
  */
-public interface PermissionServiceProvider : SingletonExtension<PermissionService<*>> {
+public interface PermissionServiceProvider : InstanceExtension<PermissionService<*>> {
+
     public companion object ExtensionPoint :
-        AbstractSingletonExtensionPoint<PermissionServiceProvider, PermissionService<*>>(
-            PermissionServiceProvider::class,
-            { BuiltInPermissionService() }
-        ) {
-        internal var permissionServiceOk = false
-
-        @ConsoleExperimentalApi
-        public val providerPlugin: Plugin? by lazy {
-            GlobalComponentStorage.run {
-                val instance = PermissionService.INSTANCE
-                if (instance is BuiltInPermissionService) return@lazy null
-                PermissionServiceProvider.getExtensions().find { it.extension.instance === instance }?.plugin
-            }
-        }
-
-        @ConsoleExperimentalApi
-        override val selectedInstance: PermissionService<*>
-            get() {
-                if (!permissionServiceOk) {
-                    error("PermissionService not yet loaded")
-                }
-                return super.selectedInstance
-            }
-    }
+        AbstractInstanceExtensionPoint<PermissionServiceProvider, PermissionService<*>>(PermissionServiceProvider::class)
+    // ! BREAKING CHANGE MADE IN 2.11: supertype changed from AbstractSingletonExtensionPoint to AbstractInstanceExtensionPoint
 }
 
 /**
  * @see PermissionServiceProvider
  */
+@Deprecated("Please implement your own PermissionServiceProvider.")
+@DeprecatedSinceMirai(warningSince = "2.11") // for hidden.
 public class PermissionServiceProviderImpl(override val instance: PermissionService<*>) : PermissionServiceProvider
 
 /**
  * @see PermissionServiceProvider
  */
+@Deprecated("Please implement your own PermissionServiceProvider.")
+@DeprecatedSinceMirai(warningSince = "2.11") // for hidden.
 public class PermissionServiceProviderImplLazy(initializer: () -> PermissionService<*>) : PermissionServiceProvider {
     override val instance: PermissionService<*> by lazy(initializer)
 }
diff --git a/mirai-console/backend/mirai-console/src/extensions/PluginLoaderProvider.kt b/mirai-console/backend/mirai-console/src/extensions/PluginLoaderProvider.kt
index 0cc1938a4..53448610f 100644
--- a/mirai-console/backend/mirai-console/src/extensions/PluginLoaderProvider.kt
+++ b/mirai-console/backend/mirai-console/src/extensions/PluginLoaderProvider.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -14,6 +14,7 @@ import net.mamoe.mirai.console.extension.Extension
 import net.mamoe.mirai.console.extension.InstanceExtension
 import net.mamoe.mirai.console.extension.PluginComponentStorage
 import net.mamoe.mirai.console.plugin.loader.PluginLoader
+import net.mamoe.mirai.utils.DeprecatedSinceMirai
 
 /**
  * 提供扩展 [PluginLoader]
@@ -30,8 +31,12 @@ public interface PluginLoaderProvider : InstanceExtension<PluginLoader<*, *>> {
     public companion object ExtensionPoint : AbstractExtensionPoint<PluginLoaderProvider>(PluginLoaderProvider::class)
 }
 
+@Deprecated("Please implement your own PluginLoaderProvider.")
+@DeprecatedSinceMirai(warningSince = "2.11") // for hidden.
 public class PluginLoaderProviderImpl(override val instance: PluginLoader<*, *>) : PluginLoaderProvider
 
+@Deprecated("Please implement your own PluginLoaderProvider.")
+@DeprecatedSinceMirai(warningSince = "2.11") // for hidden.
 public class PluginLoaderProviderImplLazy(initializer: () -> PluginLoader<*, *>) : PluginLoaderProvider {
     override val instance: PluginLoader<*, *> by lazy(initializer)
 }
\ No newline at end of file
diff --git a/mirai-console/backend/mirai-console/src/extensions/SingletonExtensionSelector.kt b/mirai-console/backend/mirai-console/src/extensions/SingletonExtensionSelector.kt
index 72f66b6c6..265e67722 100644
--- a/mirai-console/backend/mirai-console/src/extensions/SingletonExtensionSelector.kt
+++ b/mirai-console/backend/mirai-console/src/extensions/SingletonExtensionSelector.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -7,18 +7,17 @@
  * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
+@file:Suppress("DEPRECATION")
+
 package net.mamoe.mirai.console.extensions
 
 import net.mamoe.mirai.console.MiraiConsole
-import net.mamoe.mirai.console.extension.AbstractExtensionPoint
-import net.mamoe.mirai.console.extension.Extension
-import net.mamoe.mirai.console.extension.FunctionExtension
-import net.mamoe.mirai.console.extension.SingletonExtension
-import net.mamoe.mirai.console.internal.extension.SingletonExtensionSelectorImpl
-import net.mamoe.mirai.console.internal.extension.ExtensionRegistry
+import net.mamoe.mirai.console.extension.*
 import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
+import net.mamoe.mirai.console.internal.extension.SingletonExtensionSelectorImpl
 import net.mamoe.mirai.console.plugin.Plugin
 import net.mamoe.mirai.console.plugin.name
+import net.mamoe.mirai.utils.DeprecatedSinceMirai
 import net.mamoe.mirai.utils.info
 import kotlin.reflect.KClass
 
@@ -27,10 +26,20 @@ import kotlin.reflect.KClass
  *
  * 如有多个 [SingletonExtensionSelector] 注册, 将会停止服务器.
  */
+@Deprecated(
+    "Order of extensions is now determined by its priority property since 2.11. SingletonExtensionSelector is not needed anymore. ",
+    level = DeprecationLevel.WARNING
+)
+@DeprecatedSinceMirai(warningSince = "2.11")
 public interface SingletonExtensionSelector : FunctionExtension {
     /**
      * 表示一个插件注册的 [Extension]
      */
+    @Deprecated(
+        "Order of extensions is now determined by its priority property since 2.11. SingletonExtensionSelector is not needed anymore. ",
+        level = DeprecationLevel.WARNING
+    )
+    @DeprecatedSinceMirai(warningSince = "2.11")
     public data class Registry<T : Extension>(
         val plugin: Plugin?,
         val extension: T,
@@ -44,6 +53,11 @@ public interface SingletonExtensionSelector : FunctionExtension {
         candidates: Collection<Registry<T>>,
     ): T?
 
+    @Deprecated(
+        "Order of extensions is now determined by its priority property since 2.11. SingletonExtensionSelector is not needed anymore. ",
+        level = DeprecationLevel.WARNING
+    )
+    @DeprecatedSinceMirai(warningSince = "2.11")
     public companion object ExtensionPoint :
         AbstractExtensionPoint<SingletonExtensionSelector>(SingletonExtensionSelector::class) {
 
@@ -53,16 +67,22 @@ public interface SingletonExtensionSelector : FunctionExtension {
 
         internal fun init() {
             check(instanceField == null) { "Internal error: reinitialize SingletonExtensionSelector" }
-            val instances = GlobalComponentStorage.run { SingletonExtensionSelector.getExtensions() }
+            val instances = GlobalComponentStorage.getExtensions(ExtensionPoint).toList()
             instanceField = when {
                 instances.isEmpty() -> SingletonExtensionSelectorImpl
                 instances.size == 1 -> {
-                    instances.single().also { (plugin, ext) ->
-                        MiraiConsole.mainLogger.info { "Loaded SingletonExtensionSelector: $ext from ${plugin?.name ?: "<builtin>"}" }
+                    instances.single().also { registry ->
+                        MiraiConsole.mainLogger.info { "Loaded SingletonExtensionSelector: ${registry.extension} from ${registry.plugin?.name ?: "<builtin>"}" }
                     }.extension
                 }
                 else -> {
-                    error("Found too many SingletonExtensionSelectors: ${instances.joinToString { (p, i) -> "'$i' from '${p?.name ?: "<builtin>"}'" }}. Check your plugins and ensure there is only one external SingletonExtensionSelectors")
+                    val hint = instances.joinToString { reg ->
+                        "'${reg.extension}' from '${reg.plugin?.name ?: "<builtin>"}'"
+                    }
+                    error(
+                        "Found too many SingletonExtensionSelectors: $hint. " +
+                                "Check your plugins and ensure there is only one external SingletonExtensionSelectors"
+                    )
                 }
             }
         }
diff --git a/mirai-console/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt b/mirai-console/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt
index b8448aedc..4434fc256 100644
--- a/mirai-console/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt
+++ b/mirai-console/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt
@@ -22,9 +22,13 @@ import net.mamoe.mirai.console.MiraiConsoleImplementation
 import net.mamoe.mirai.console.command.BuiltInCommands
 import net.mamoe.mirai.console.command.CommandManager
 import net.mamoe.mirai.console.command.ConsoleCommandSender
+import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
+import net.mamoe.mirai.console.command.parse.SpaceSeparatedCommandCallParser
+import net.mamoe.mirai.console.command.resolve.BuiltInCommandCallResolver
+import net.mamoe.mirai.console.extensions.CommandCallParserProvider
+import net.mamoe.mirai.console.extensions.CommandCallResolverProvider
 import net.mamoe.mirai.console.extensions.PermissionServiceProvider
 import net.mamoe.mirai.console.extensions.PostStartupExtension
-import net.mamoe.mirai.console.extensions.SingletonExtensionSelector
 import net.mamoe.mirai.console.internal.command.CommandConfig
 import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig
 import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.ConfigurationKey
@@ -32,7 +36,7 @@ import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.Pa
 import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.PasswordKind.PLAIN
 import net.mamoe.mirai.console.internal.data.builtins.LoggerConfig
 import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
-import net.mamoe.mirai.console.internal.extension.SingletonExtensionSelectorImpl
+import net.mamoe.mirai.console.internal.extension.GlobalComponentStorageImpl
 import net.mamoe.mirai.console.internal.logging.LoggerControllerImpl
 import net.mamoe.mirai.console.internal.logging.MiraiConsoleLogger
 import net.mamoe.mirai.console.internal.permission.BuiltInPermissionService
@@ -77,6 +81,9 @@ internal class MiraiConsoleImplementationBridge(
     override val version: SemVersion by MiraiConsoleBuildConstants::version
     override val pluginManager: PluginManagerImpl by lazy { PluginManagerImpl(coroutineContext) }
 
+    // used internally
+    val globalComponentStorage: GlobalComponentStorageImpl by lazy { GlobalComponentStorageImpl() }
+
     override val mainLogger: MiraiLogger by lazy { createLogger("main") }
 
     init {
@@ -99,6 +106,15 @@ internal class MiraiConsoleImplementationBridge(
     internal fun doStart() {
         externalImplementation.preStart()
 
+        @OptIn(ExperimentalCommandDescriptors::class)
+        phase("register builtin componenets") {
+            GlobalComponentStorage.run {
+                contributeConsole(CommandCallParserProvider, SpaceSeparatedCommandCallParser.Provider)
+                contributeConsole(CommandCallResolverProvider, BuiltInCommandCallResolver.Provider)
+                contributeConsole(PermissionServiceProvider, BuiltInPermissionService.Provider())
+            }
+        }
+
         phase("setup logger controller") {
             if (loggerController === LoggerControllerImpl) {
                 // Reload LoggerConfig.
@@ -159,25 +175,30 @@ internal class MiraiConsoleImplementationBridge(
             mainLogger.verbose { "${PluginManager.plugins.size} plugin(s) loaded." }
         }
 
-        phase("load SingletonExtensionSelector") {
-            SingletonExtensionSelector.init()
-            val instance = SingletonExtensionSelector.instance
-            if (instance is SingletonExtensionSelectorImpl) {
-                consoleDataScope.addAndReloadConfig(instance.config)
-            }
-        }
+//        phase("load SingletonExtensionSelector") {
+//            SingletonExtensionSelector.init()
+//            val instance = SingletonExtensionSelector.instance
+//            if (instance is SingletonExtensionSelectorImpl) {
+//                consoleDataScope.addAndReloadConfig(instance.config)
+//            }
+//        }
 
 
         phase("load PermissionService") {
             mainLogger.verbose { "Loading PermissionService..." }
 
-            PermissionServiceProvider.permissionServiceOk = true
             PermissionService.INSTANCE.let { ps ->
                 if (ps is BuiltInPermissionService) {
                     consoleDataScope.addAndReloadConfig(ps.config)
                     mainLogger.verbose { "Reloaded PermissionService settings." }
                 } else {
-                    mainLogger.info { "Loaded PermissionService from plugin ${PermissionServiceProvider.providerPlugin?.name}" }
+                    mainLogger.info {
+                        "Loaded PermissionService from plugin ${
+                            GlobalComponentStorage.getPreferredExtension(
+                                PermissionServiceProvider
+                            ).plugin?.name
+                        }"
+                    }
                 }
             }
 
@@ -258,9 +279,7 @@ internal class MiraiConsoleImplementationBridge(
         }
 
         phase("finally post") {
-            GlobalComponentStorage.run {
-                PostStartupExtension.useExtensions { it() } // exceptions thrown will be caught by caller of `doStart`.
-            }
+            globalComponentStorage.useEachExtensions(PostStartupExtension) { it.invoke() }
         }
 
         externalImplementation.postStart()
diff --git a/mirai-console/backend/mirai-console/src/internal/extension/ComponentStorageInternal.kt b/mirai-console/backend/mirai-console/src/internal/extension/ComponentStorageInternal.kt
index 5e8d4a755..618f7e849 100644
--- a/mirai-console/backend/mirai-console/src/internal/extension/ComponentStorageInternal.kt
+++ b/mirai-console/backend/mirai-console/src/internal/extension/ComponentStorageInternal.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -10,140 +10,116 @@
 package net.mamoe.mirai.console.internal.extension
 
 import net.mamoe.mirai.console.extension.*
-import net.mamoe.mirai.console.extensions.SingletonExtensionSelector
-import net.mamoe.mirai.console.extensions.SingletonExtensionSelector.ExtensionPoint.selectSingleton
+import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
 import net.mamoe.mirai.console.internal.data.kClassQualifiedNameOrTip
 import net.mamoe.mirai.console.plugin.Plugin
 import net.mamoe.mirai.console.plugin.name
+import java.util.*
 import java.util.concurrent.ConcurrentHashMap
-import java.util.concurrent.CopyOnWriteArraySet
+import java.util.stream.Stream
 import kotlin.contracts.contract
-import kotlin.reflect.KClass
+
+internal class GlobalComponentStorageImpl : AbstractConcurrentComponentStorage()
+
+// source compatibility for <2.11
+internal val GlobalComponentStorage get() = MiraiConsoleImplementationBridge.globalComponentStorage
 
 /**
- * The [ComponentStorage] containing all components provided by Mirai Console internals and installed plugins.
+ * thread-safe.
  */
-internal object GlobalComponentStorage : AbstractConcurrentComponentStorage()
-internal interface ExtensionRegistry<out E : Extension> {
-    val plugin: Plugin?
-    val extension: E
+internal abstract class AbstractConcurrentComponentStorage : ComponentStorage, ComponentStorageInternal {
+    ///////////////////////////////////////////////////////////////////////////
+    // registry implementation
+    ///////////////////////////////////////////////////////////////////////////
 
-    operator fun component1(): Plugin? {
-        return this.plugin
-    }
+    /**
+     * For each [ExtensionPoint]. thread-safe.
+     */
+    internal class Registries<T : Extension> {
+        @Volatile
+        private var data: MutableCollection<ExtensionRegistry<T>> = ArrayList()
+        private val lock = Any()
 
-    operator fun component2(): E {
-        return this.extension
-    }
-}
-
-internal class LazyExtensionRegistry<out E : Extension>(
-    override val plugin: Plugin?,
-    initializer: () -> E,
-) : ExtensionRegistry<E> {
-    override val extension: E by lazy { initializer() }
-}
-
-internal data class DataExtensionRegistry<out E : Extension>(
-    override val plugin: Plugin?,
-    override val extension: E,
-) : ExtensionRegistry<E>
-
-internal abstract class AbstractConcurrentComponentStorage : ComponentStorage {
-    private val instances: MutableMap<ExtensionPoint<*>, MutableSet<ExtensionRegistry<*>>> = ConcurrentHashMap()
-
-    @Suppress("UNCHECKED_CAST")
-    internal fun <T : Extension> ExtensionPoint<out T>.getExtensions(): Set<ExtensionRegistry<T>> {
-        val userDefined = instances.getOrPut(this, ::CopyOnWriteArraySet) as Set<ExtensionRegistry<T>>
-
-        val builtins = if (this is AbstractInstanceExtensionPoint<*, *>) {
-            this.builtinImplementations.mapTo(HashSet()) { instance ->
-                DataExtensionRegistry(
-                    null,
-                    instance()
+        fun register(registry: ExtensionRegistry<T>) {
+            synchronized(lock) {
+                val list = PriorityQueue(
+                    data.size + 1,
+                    Comparator.comparing<ExtensionRegistry<T>, Int> { it.extension.priority }.reversed()
                 )
-            } as Set<ExtensionRegistry<T>>
-        } else null
-
-        return builtins?.plus(userDefined) ?: userDefined
-    }
-
-    // unused for now
-    internal fun removeExtensionsRegisteredByPlugin(plugin: Plugin) {
-        instances.forEach { (_, u) ->
-            u.removeAll { it.plugin == plugin }
+                list.addAll(data)
+                list.add(registry)
+                data = list
+            }
         }
+
+        /**
+         * @return thread-safe Sequence
+         */
+        fun asSequence(): Sequence<ExtensionRegistry<T>> = data.asSequence()
+
+        /**
+         * @return thread-safe Sequence
+         */
+        fun asStream(): Stream<ExtensionRegistry<T>> = data.stream()
     }
 
+    private val registries: MutableMap<ExtensionPoint<*>, Registries<*>> = ConcurrentHashMap()
+
+    private fun <T : Extension> getRegistries(ep: ExtensionPoint<T>): Registries<T> {
+        @Suppress("UNCHECKED_CAST")
+        return registries.getOrPut(ep) { Registries<T>() } as Registries<T>
+    }
+
+    private fun <T : Extension> registerExtension(ep: ExtensionPoint<T>, registry: ExtensionRegistry<T>) {
+        getRegistries(ep).register(registry)
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // public API implementation
+    ///////////////////////////////////////////////////////////////////////////
+
+
     internal fun mergeWith(another: AbstractConcurrentComponentStorage) {
-        for ((ep, list) in another.instances) {
-            for (extensionRegistry in list) {
+        another.registries.forEach { (ep, registries) ->
+            for (extensionRegistry in registries.asSequence()) {
                 @Suppress("UNCHECKED_CAST")
                 ep as ExtensionPoint<Extension>
-                this.contribute(ep, extensionRegistry.plugin, lazyInstance = { extensionRegistry.extension })
+                registerExtension(ep, ExtensionRegistryImpl(extensionRegistry.plugin) { extensionRegistry.extension })
             }
         }
     }
 
-    internal inline fun <T : Extension> ExtensionPoint<out T>.withExtensions(block: T.() -> Unit) {
-        return withExtensions { _ -> block() }
-    }
-
-    @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
-    @kotlin.internal.LowPriorityInOverloadResolution
-    internal inline fun <T : Extension> ExtensionPoint<out T>.withExtensions(block: T.(plugin: Plugin?) -> Unit) {
-        contract {
-            callsInPlace(block)
-        }
-        for ((plugin, extension) in this.getExtensions()) {
+    internal inline fun <T : Extension> useEachExtensions(
+        extensionPoint: ExtensionPoint<T>,
+        block: ExtensionRegistry<T>.(instance: T) -> Unit
+    ) {
+        contract { callsInPlace(block) }
+        getExtensions(extensionPoint).forEach { registry ->
+            val plugin = registry.plugin
+            val extension = registry.extension
             kotlin.runCatching {
-                block.invoke(extension, plugin)
+                block.invoke(registry, registry.extension)
             }.getOrElse { throwable ->
-                throwExtensionException(extension, plugin, throwable)
+                extensionPoint.throwExtensionException(extension, plugin, throwable)
             }
         }
     }
 
-    internal inline fun <reified E : SingletonExtension<*>> ExtensionPoint<out E>.findSingleton(builtin: E): E =
-        findSingleton(E::class, builtin)
-
-    internal fun <E : SingletonExtension<*>> ExtensionPoint<out E>.findSingleton(type: KClass<E>, builtin: E): E {
-        val candidates = this.getExtensions()
-        return when (candidates.size) {
-            0 -> builtin
-            1 -> candidates.single().extension
-            else -> SingletonExtensionSelector.instance.selectSingleton(type, candidates) ?: builtin
-        }
-    }
-
-    internal inline fun <reified E : SingletonExtension<T>, T> ExtensionPoint<out E>.findSingletonInstance(noinline default: () -> T): T =
-        findSingletonInstance(E::class, default)
-
-    internal fun <E : SingletonExtension<T>, T> ExtensionPoint<out E>.findSingletonInstance(
-        type: KClass<E>,
-        default: () -> T,
-    ): T {
-        val candidates = this.getExtensions()
-        return when (candidates.size) {
-            0 -> default()
-            1 -> candidates.single().extension.instance
-            else -> SingletonExtensionSelector.instance.selectSingleton(type, candidates)?.instance ?: default()
-        }
-    }
-
-    internal inline fun <T : Extension, E> ExtensionPoint<out T>.foldExtensions(
+    internal inline fun <T : Extension, E> foldExtensions(
+        extensionPoint: ExtensionPoint<T>,
         initial: E,
         block: (acc: E, extension: T) -> E,
     ): E {
-        contract {
-            callsInPlace(block)
-        }
+        contract { callsInPlace(block) }
         var e: E = initial
-        for ((plugin, extension) in this.getExtensions()) {
+        getExtensions(extensionPoint).forEach { registry ->
+            val plugin = registry.plugin
+            val extension = registry.extension
             kotlin.runCatching {
                 e = block.invoke(e, extension)
             }.getOrElse { throwable ->
-                throwExtensionException(extension, plugin, throwable)
+                extensionPoint.throwExtensionException(extension, plugin, throwable)
             }
         }
         return e
@@ -153,52 +129,38 @@ internal abstract class AbstractConcurrentComponentStorage : ComponentStorage {
         extension: T,
         plugin: Plugin?,
         throwable: Throwable,
-    ) {
+    ): Nothing {
         throw ExtensionException(
             "Exception while executing extension '${extension.kClassQualifiedNameOrTip}' provided by plugin '${plugin?.name ?: "<builtin>"}', registered for '${this.extensionType.qualifiedName}'",
             throwable
         )
     }
 
-    internal inline fun <T : Extension> ExtensionPoint<T>.useExtensions(block: (extension: T) -> Unit): Unit =
-        withExtensions(block)
-
-    @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
-    @kotlin.internal.LowPriorityInOverloadResolution
-    internal inline fun <T : Extension> ExtensionPoint<T>.useExtensions(block: (extension: T, plugin: Plugin?) -> Unit): Unit =
-        withExtensions(block)
-
-    override fun <T : Extension> contribute(
-        extensionPoint: ExtensionPoint<T>,
+    override fun <E : Extension> contribute(
+        extensionPoint: ExtensionPoint<E>,
         plugin: Plugin,
-        extensionInstance: T,
+        extensionInstance: E,
     ) {
-        instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(DataExtensionRegistry(plugin, extensionInstance))
+        registerExtension(extensionPoint, ExtensionRegistryImpl(plugin) { extensionInstance })
     }
 
-    @JvmName("contribute1")
-    fun <T : Extension> contribute(
-        extensionPoint: ExtensionPoint<T>,
-        plugin: Plugin?,
-        extensionInstance: T,
-    ) {
-        instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(DataExtensionRegistry(plugin, extensionInstance))
+    override fun <E : Extension> contributeConsole(extensionPoint: ExtensionPoint<E>, lazyInstance: () -> E) {
+        registerExtension(extensionPoint, ExtensionRegistryImpl(null, lazyInstance))
     }
 
-    override fun <T : Extension> contribute(
-        extensionPoint: ExtensionPoint<T>,
+    override fun <E : Extension> contribute(
+        extensionPoint: ExtensionPoint<E>,
         plugin: Plugin,
-        lazyInstance: () -> T,
+        lazyInstance: () -> E,
     ) {
-        instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(LazyExtensionRegistry(plugin, lazyInstance))
+        registerExtension(extensionPoint, ExtensionRegistryImpl(plugin, lazyInstance))
     }
 
-    @JvmName("contribute1")
-    fun <T : Extension> contribute(
-        extensionPoint: ExtensionPoint<T>,
-        plugin: Plugin?,
-        lazyInstance: () -> T,
-    ) {
-        instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(LazyExtensionRegistry(plugin, lazyInstance))
+    override fun <E : Extension> getExtensions(extensionPoint: ExtensionPoint<E>): Sequence<ExtensionRegistry<E>> {
+        return getRegistries(extensionPoint).asSequence()
+    }
+
+    override fun <E : Extension> getExtensionsStream(extensionPoint: ExtensionPoint<E>): Stream<ExtensionRegistry<E>> {
+        return getRegistries(extensionPoint).asStream()
     }
 }
\ No newline at end of file
diff --git a/mirai-console/backend/mirai-console/src/internal/extension/SingletonExtensionSelectorImpl.kt b/mirai-console/backend/mirai-console/src/internal/extension/SingletonExtensionSelectorImpl.kt
index 0714840a7..a630c6a9d 100644
--- a/mirai-console/backend/mirai-console/src/internal/extension/SingletonExtensionSelectorImpl.kt
+++ b/mirai-console/backend/mirai-console/src/internal/extension/SingletonExtensionSelectorImpl.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -18,9 +18,16 @@ import net.mamoe.mirai.console.extensions.SingletonExtensionSelector
 import net.mamoe.mirai.console.internal.data.kClassQualifiedName
 import net.mamoe.mirai.console.plugin.name
 import net.mamoe.mirai.console.util.ConsoleInput
+import net.mamoe.mirai.utils.DeprecatedSinceMirai
 import net.mamoe.mirai.utils.info
 import kotlin.reflect.KClass
 
+@Suppress("DEPRECATION")
+@Deprecated(
+    "Order of extensions is not determined by its priority property since 2.11. SingletonExtensionSelector is not needed anymore. ",
+    level = DeprecationLevel.WARNING
+)
+@DeprecatedSinceMirai(warningSince = "2.11")
 internal object SingletonExtensionSelectorImpl : SingletonExtensionSelector {
 
     internal val config: SaveData = SaveData()
diff --git a/mirai-console/backend/mirai-console/src/internal/permission/BuiltInPermissionServices.kt b/mirai-console/backend/mirai-console/src/internal/permission/BuiltInPermissionServices.kt
index 2b5653783..3c320c514 100644
--- a/mirai-console/backend/mirai-console/src/internal/permission/BuiltInPermissionServices.kt
+++ b/mirai-console/backend/mirai-console/src/internal/permission/BuiltInPermissionServices.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -14,6 +14,7 @@ import net.mamoe.mirai.console.data.AutoSavePluginConfig
 import net.mamoe.mirai.console.data.PluginDataExtensions
 import net.mamoe.mirai.console.data.PluginDataExtensions.withDefault
 import net.mamoe.mirai.console.data.value
+import net.mamoe.mirai.console.extensions.PermissionServiceProvider
 import net.mamoe.mirai.console.permission.*
 import java.util.concurrent.ConcurrentHashMap
 import java.util.concurrent.CopyOnWriteArraySet
@@ -100,6 +101,12 @@ internal class AllDenyPermissionService : PermissionService<PermissionImpl> {
 internal class BuiltInPermissionService : AbstractConcurrentPermissionService<PermissionImpl>(),
     PermissionService<PermissionImpl> {
 
+    class Provider : PermissionServiceProvider {
+        override val instance: PermissionService<*> by lazy {
+            BuiltInPermissionService()
+        }
+    }
+
     override val permissionType: KClass<PermissionImpl>
         get() = PermissionImpl::class
     override val permissions: ConcurrentHashMap<PermissionId, PermissionImpl> = ConcurrentHashMap()
diff --git a/mirai-console/backend/mirai-console/src/internal/plugin/PluginManagerImpl.kt b/mirai-console/backend/mirai-console/src/internal/plugin/PluginManagerImpl.kt
index c2d744f30..ecbe86aed 100644
--- a/mirai-console/backend/mirai-console/src/internal/plugin/PluginManagerImpl.kt
+++ b/mirai-console/backend/mirai-console/src/internal/plugin/PluginManagerImpl.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -160,12 +160,10 @@ internal class PluginManagerImpl(
 
     internal fun initExternalPluginLoaders(): Int {
         var count = 0
-        GlobalComponentStorage.run {
-            PluginLoaderProvider.useExtensions { ext, plugin ->
-                logger.info { "Loaded PluginLoader ${ext.instance} from ${plugin?.name ?: "<builtin>"}" }
-                _pluginLoaders.add(ext.instance)
-                count++
-            }
+        GlobalComponentStorage.useEachExtensions(PluginLoaderProvider) {
+            logger.info { "Loaded PluginLoader ${extension.instance} from ${plugin?.name ?: "<builtin>"}" }
+            _pluginLoaders.add(extension.instance)
+            count++
         }
         return count
     }
diff --git a/mirai-console/backend/mirai-console/src/permission/PermissionService.kt b/mirai-console/backend/mirai-console/src/permission/PermissionService.kt
index 9542ed089..e91af577a 100644
--- a/mirai-console/backend/mirai-console/src/permission/PermissionService.kt
+++ b/mirai-console/backend/mirai-console/src/permission/PermissionService.kt
@@ -1,10 +1,10 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
- *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  *
- *  https://github.com/mamoe/mirai/blob/master/LICENSE
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
 @file:Suppress("NOTHING_TO_INLINE", "unused", "MemberVisibilityCanBePrivate")
@@ -13,7 +13,9 @@ package net.mamoe.mirai.console.permission
 
 import net.mamoe.mirai.console.compiler.common.ResolveContext
 import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.COMMAND_NAME
+import net.mamoe.mirai.console.extension.instance
 import net.mamoe.mirai.console.extensions.PermissionServiceProvider
+import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
 import net.mamoe.mirai.console.internal.permission.checkType
 import net.mamoe.mirai.console.permission.Permission.Companion.parentsWithSelf
 import net.mamoe.mirai.console.plugin.Plugin
@@ -140,14 +142,12 @@ public interface PermissionService<P : Permission> {
 
     public companion object {
         /**
-         * [PermissionService] 实例
-         *
-         * @see PermissionServiceProvider.selectedInstance
+         * 选用的 [PermissionService] 实例.
          */
         @get:JvmName("getInstance")
         @JvmStatic
         public val INSTANCE: PermissionService<out Permission>
-            get() = PermissionServiceProvider.selectedInstance
+            get() = GlobalComponentStorage.getPreferredExtension(PermissionServiceProvider).instance
 
         /**
          * 获取一个权限, 失败时抛出 [NoSuchElementException]
diff --git a/mirai-console/backend/mirai-console/test/extension/GlobalComponentStorageTest.kt b/mirai-console/backend/mirai-console/test/extension/GlobalComponentStorageTest.kt
new file mode 100644
index 000000000..450385faf
--- /dev/null
+++ b/mirai-console/backend/mirai-console/test/extension/GlobalComponentStorageTest.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+package net.mamoe.mirai.console.extension
+
+import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
+import net.mamoe.mirai.console.internal.extension.GlobalComponentStorageImpl
+import net.mamoe.mirai.console.testFramework.AbstractConsoleInstanceTest
+import org.junit.jupiter.api.Test
+import kotlin.test.assertEquals
+
+internal class GlobalComponentStorageTest : AbstractConsoleInstanceTest() {
+    class MyInstance
+
+    class MyExtension(override val instance: MyInstance, override val priority: Int) : InstanceExtension<MyInstance> {
+        companion object EP : AbstractInstanceExtensionPoint<MyExtension, MyInstance>(MyExtension::class)
+    }
+
+    @Test
+    fun `can register`() {
+        GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 1))
+        GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 2))
+        GlobalComponentStorage.getExtensionsList(MyExtension).run {
+            assertEquals(2, size)
+        }
+    }
+
+    @Test
+    fun `can contribute`() {
+        GlobalComponentStorage.contribute(MyExtension, mockPlugin, MyExtension(MyInstance(), 1))
+        GlobalComponentStorage.contribute(MyExtension, mockPlugin, MyExtension(MyInstance(), 2))
+        GlobalComponentStorage.getExtensionsList(MyExtension).run {
+            assertEquals(2, size)
+        }
+    }
+
+    @Test
+    fun `can sort by priority`() {
+        GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 1))
+        GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 2))
+        GlobalComponentStorage.getExtensionsList(MyExtension).run {
+            assertEquals(2, size)
+            assertEquals(2, first().extension.priority)
+            assertEquals(1, get(1).extension.priority)
+        }
+    }
+
+    @Test
+    fun `can sort by priority 2`() {
+        GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 2))
+        GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 1))
+        GlobalComponentStorage.getExtensionsList(MyExtension).run {
+            assertEquals(2, size)
+            assertEquals(2, first().extension.priority)
+            assertEquals(1, get(1).extension.priority)
+        }
+    }
+
+    @Test
+    fun `can fold`() {
+        GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 2))
+        GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 1))
+        val list = GlobalComponentStorage.foldExtensions(MyExtension, listOf<MyExtension>()) { acc, extension ->
+            acc + extension
+        }
+        assertEquals(2, list.size)
+        assertEquals(2, list.first().priority)
+        assertEquals(1, list[1].priority)
+    }
+}
+
+private fun <T : Extension> GlobalComponentStorageImpl.getExtensionsList(ep: ExtensionPoint<T>): List<ExtensionRegistry<T>> {
+    return getExtensions(ep).toList()
+}
\ No newline at end of file