实例与功能系统
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()
endinitInstanceWithConfig() 中的关键步骤
应用功能:遍历
config.App(分发器、路由器、DNS、策略、统计等),通过CreateObject()创建对象,注册为功能。必要的默认组件:如果 DNS、Policy、Router 或 Stats 未配置,则注册默认(空操作)实现:
goessentialFeatures := []struct{ Type, Instance }{ {dns.ClientType(), localdns.New()}, {policy.ManagerType(), policy.DefaultManager{}}, {routing.RouterType(), routing.DefaultRouter{}}, {stats.ManagerType(), stats.NoopManager{}}, }系统拨号器初始化:使用 DNS 客户端和出站管理器配置全局系统拨号器(用于
freedom出站的 DNS 解析)。依赖检查:如果
pendingResolutions中仍有未解析的依赖,则报错。处理器注册:添加所有入站和出站处理器。
依赖解析
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() 时:
- 检查所有参数类型是否已注册
- 如果是,立即调用回调函数
- 如果否,将其作为
resolution存储在pendingResolutions中 - 每次调用
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 系统:
- 需要一个功能注册表,将功能类型映射到实例
- 需要一个依赖解析器,在所有依赖满足时触发回调
- 需要一个配置反序列化器,将配置类型映射到构造函数
- 功能生命周期:注册 → 依赖解析 → 启动 → 关闭
基于反射的方法可以在静态类型语言中替换为显式注册:
instance.addFeature(dispatcherFeature)
instance.addFeature(routerFeature)
// Router 发现 dispatcher 已可用,解析其依赖