Skip to content

实例与功能系统

core.Instance 是持有所有功能(DNS、路由、代理管理器等)并管理其生命周期的核心对象。

实例结构

go
// core/xray.go
type Instance struct {
    statusLock                 sync.Mutex
    features                   []features.Feature
    pendingResolutions         []resolution
    pendingOptionalResolutions []resolution
    running                    bool
    resolveLock                sync.Mutex
    ctx                        context.Context
}

实例本质上是一个依赖注入容器。功能组件自行注册,其他功能组件可以声明依赖关系,当所有必需的功能可用时,依赖会自动解析。

功能接口

每个主要组件都实现了 features.Feature 接口:

go
// features/feature.go
type Feature interface {
    common.HasType   // Type() interface{}
    common.Runnable  // Start() error, Close() error
}

功能类型通过哨兵指针值进行标识:

go
func ManagerType() interface{} { return (*Manager)(nil) }
func ClientType() interface{}  { return (*Client)(nil) }

初始化流程

mermaid
sequenceDiagram
    participant Config as 配置
    participant Instance as 实例
    participant Feature as 功能
    participant InboundMgr as 入站管理器
    participant OutboundMgr as 出站管理器

    Config->>Instance: New(config)
    loop 遍历每个应用配置
        Instance->>Instance: CreateObject(settings)
        Instance->>Feature: AddFeature(feature)
        Feature-->>Instance: 解析待处理的依赖
    end
    Note over Instance: 自动注册默认组件<br/>(DNS、Policy、Router、Stats)
    Instance->>Instance: InitSystemDialer(dns, obm)
    Instance->>Instance: 检查:所有依赖是否已解析?
    loop 遍历每个入站配置
        Instance->>InboundMgr: AddHandler(handler)
    end
    loop 遍历每个出站配置
        Instance->>OutboundMgr: AddHandler(handler)
    end
    Note over Instance: 实例就绪(尚未启动)
    Instance->>Instance: Start()
    loop 遍历每个功能
        Instance->>Feature: Start()
    end

initInstanceWithConfig() 中的关键步骤

  1. 应用功能:遍历 config.App(分发器、路由器、DNS、策略、统计等),通过 CreateObject() 创建对象,注册为功能。

  2. 必要的默认组件:如果 DNS、Policy、Router 或 Stats 未配置,则注册默认(空操作)实现:

    go
    essentialFeatures := []struct{ Type, Instance }{
        {dns.ClientType(), localdns.New()},
        {policy.ManagerType(), policy.DefaultManager{}},
        {routing.RouterType(), routing.DefaultRouter{}},
        {stats.ManagerType(), stats.NoopManager{}},
    }
  3. 系统拨号器初始化:使用 DNS 客户端和出站管理器配置全局系统拨号器(用于 freedom 出站的 DNS 解析)。

  4. 依赖检查:如果 pendingResolutions 中仍有未解析的依赖,则报错。

  5. 处理器注册:添加所有入站和出站处理器。

依赖解析

RequireFeatures() 机制实现了延迟依赖注入:

go
// 组件声明其所需的依赖:
core.RequireFeatures(ctx, func(om outbound.Manager, router routing.Router,
    pm policy.Manager, sm stats.Manager, dc dns.Client) error {
    return d.Init(config, om, router, pm, sm)
})

当调用 RequireFeatures() 时:

  1. 检查所有参数类型是否已注册
  2. 如果是,立即调用回调函数
  3. 如果否,将其作为 resolution 存储在 pendingResolutions
  4. 每次调用 AddFeature() 时,重新检查所有待处理的解析

解析过程使用反射来匹配参数类型:

go
type resolution struct {
    deps     []reflect.Type      // 所需的功能类型
    callback interface{}         // func(features...) error
}

对象创建

CreateObject() 是将 protobuf 配置转换为运行时对象的工厂函数:

go
// 从 core/config.go 调用
func CreateObject(server *Instance, config interface{}) (interface{}, error) {
    ctx := context.WithValue(server.ctx, xrayKey, server)
    return common.CreateObject(ctx, config)
}

此函数调用配置注册表,其中每个 protobuf 类型都映射到通过 common.RegisterConfig() 注册的构造函数。

配置注册模式

每个组件都遵循以下模式:

go
func init() {
    common.Must(common.RegisterConfig((*Config)(nil),
        func(ctx context.Context, config interface{}) (interface{}, error) {
            c := config.(*Config)
            // 从配置构建运行时对象
            return NewHandler(ctx, c)
        }))
}

protobuf Config 类型作为键,工厂函数创建运行时对象。TypedMessage 包装器(protobuf Any)提供类型安全的反序列化。

实现说明

要重新实现 Instance 系统:

  1. 需要一个功能注册表,将功能类型映射到实例
  2. 需要一个依赖解析器,在所有依赖满足时触发回调
  3. 需要一个配置反序列化器,将配置类型映射到构造函数
  4. 功能生命周期:注册 → 依赖解析 → 启动 → 关闭

基于反射的方法可以在静态类型语言中替换为显式注册:

instance.addFeature(dispatcherFeature)
instance.addFeature(routerFeature)
// Router 发现 dispatcher 已可用,解析其依赖

用于重新实现目的的技术分析。