LoxodonFramework服务容器与上下文详解:ApplicationContext、PlayerContext与依赖注入完全指南
【免费下载链接】loxodon-frameworkLoxodonFramework是一个轻量级的MVVM(Model-View-ViewModel)框架,它是专门为Unity3D游戏开发设计的,参考了WPF和Android的MVVM设计,它提供了视图和视图模型的数据绑定、本地化、一个简单的对象容器、配置文件组件、线程工具组件、应用上下文和玩家上下文,异步线程和协程的任务组件等基本组件,同时还提供了一个UI视图的框架。所有代码都基于面向对象面向接口的思路设计,几乎所有功能都可以自定义。而且在数据绑定部分进行了性能优化,避免值类型装箱拆箱,最小化垃圾回收的开销,使用动态委托/静态织入技术确保数据绑定和直接调用有相当的性能,0GC更新UI视图等等,它支持绑定到UGUI、UIToolkit和FairyGUI控件,同时也很容易扩展对其他UI控件的支持。此外,它已经在项目中得到验证(UWA评分SSS级,可在战斗中完全关闭GC,在6、7前手机都保证60FPS),性能优越,稳定可靠,架构清晰,可灵活扩展。 我们希望它能够帮助您更快、更轻松地开发游戏。 本框架使用C#语言开发,同时也支持使用XLua或者ILRuntime来开发,如果项目需要热更新,那么只要安装了XLua或者ILRuntime插件,则可以完全使用Lua或者ILRuntime来开发游戏。对于新立项的项目,建议使用HybridCLR来做热更新。 这个插件兼容 MacOSX,Windows,Linux,UWP,IOS and Android,WebGL等等,并且完全开源。项目地址: https://gitcode.com/vovgou/loxodon-framework
LoxodonFramework 是专为 Unity3D 游戏开发设计的轻量级 MVVM 框架,它内置了服务容器(ServiceContainer)与两级上下文机制——应用上下文(ApplicationContext)和玩家上下文(PlayerContext),通过简单的注册/解析实现依赖注入,帮你统一管理全局服务与玩家私有数据,避免单例满天飞。本文用最少代码带你彻底搞懂这套机制。
为什么游戏需要"服务容器 + 上下文"?
传统写法里,全局服务常常靠静态单例硬编码,导致:
- 模块之间强耦合,测试困难;
- 玩家切换账号时数据残留、内存泄漏;
- 全局服务与玩家私有服务混在一起,无法按生命周期释放。
LoxodonFramework 的解法是:服务注册进容器,容器挂在上下文上,上下文按"全局 / 玩家"分层。核心源码都在Contexts与Services目录:
| 核心类 | 职责 | 源码位置 |
|---|---|---|
Context | 上下文基类,管理属性字典 + 服务容器,支持级联查找 | Context.cs |
ApplicationContext | 全局唯一的应用上下文,存放全局共享服务 | ApplicationContext.cs |
PlayerContext | 按玩家创建的上下文,存放玩家私有数据与服务 | PlayerContext.cs |
ServiceContainer | 依赖注入容器,按类型或名称注册/解析服务 | ServiceContainer.cs |
应用上下文(ApplicationContext):全局服务的单一入口
应用上下文是全局单例,在引擎场景加载前自动创建(Context内置了BeforeSceneLoad初始化),你无需手动 new。所有在整个游戏中共享的基础服务——数据绑定服务、视图定位、本地化、资源加载、日志等——都应注册到它身上。
// 获得全局的应用上下文 ApplicationContext context = Context.GetApplicationContext(); // 获得上下文中的服务容器 IServiceContainer container = context.GetContainer(); // 初始化并启动数据绑定服务(一组服务,统一通过 ServiceBundle 注册) BindingServiceBundle bindingService = new BindingServiceBundle(container); bindingService.Start(); // 从全局上下文解析服务 IUIViewLocator locator = context.GetService<IUIViewLocator>(); Localization localization = context.GetService<Localization>();ApplicationContext还额外提供了几个便捷能力(见 ApplicationContext.cs):
GetMainLoopExcutor():获取主线程执行器,方便在任意位置投递主线程任务;GetGlobalPreferences()/GetUserPreferences(name):获取全局/用户偏好设置,天然配合玩家隔离。
官方教程里的标准用法可以参考 DatabindingExample.cs。
依赖注入怎么做?ServiceContainer 的注册与解析
ServiceContainer内部使用线程安全的并发字典,同时维护类型 → 服务和名称 → 服务两套映射,支持四种常见注册方式:
// 1. 按类型注册单例(所有解析都拿到同一个实例) container.Register<IKnapsackService>(new KnapsackService()); // 2. 按名称注册单例 container.Register("http", new HttpClient()); // 3. 按类型注册工厂(每次解析都创建新实例) container.Register<ILog>(() => new FileLog()); // 4. 按名称注册工厂 container.Register("cache", () => new MemoryCache()); // 解析 IKnapsackService knapsack = context.GetService<IKnapsackService>(); object log = container.Resolve(typeof(ILog)); // 注销 container.Unregister<IKnapsackService>();📌 几个必须知道的细节:
- 重复注册同名/同类型会抛异常(
DuplicateRegisterServiceException),帮你提前发现配置错误; - 非泛型类型按类型注册后,还可以用类型名字符串解析,字符串与类型双通道查找;
- 按名称注册的服务只能用名称解析;
- 解析不到时返回
null/default,不会抛异常,调用方需自行判空。
玩家上下文(PlayerContext):玩家数据隔离的最佳实践
玩家上下文只与当前登录的玩家相关。玩家 Clark 的背包、角色信息、个人配置都该放在他的玩家上下文里;切换账号时调用一次Dispose(),该玩家注册的所有服务会被自动注销、相关IDisposable服务会被释放,天然避免账号数据串味和内存泄漏。
// 为玩家 clark 创建一个玩家上下文 PlayerContext playerContext = new PlayerContext("clark"); // 玩家上下文默认继承全局上下文(contextBase = ApplicationContext) playerContext.Set("roleInfo", roleInfo); // 玩家私有服务注册到玩家上下文的服务容器 playerContext.GetContainer().Register<IKnapsackService>(new KnapsackService()); // 玩家私有服务优先,全局服务自动"穿透"获取 IUIViewLocator locator = playerContext.GetService<IUIViewLocator>(); // 玩家退出登录时,释放整个玩家上下文 playerContext.Dispose();级联查找:玩家上下文如何"看到"全局服务?
Context的查找逻辑是先查自己,再查父上下文(见 Context.cs):
GetService<T>():先在玩家容器的Resolve中找,找不到再递归到应用上下文;- 玩家上下文注册了与全局同 Key的服务时,数据只存在玩家上下文,不会覆盖全局数据,访问时玩家级优先。
这意味着你可以在战斗代码里只依赖PlayerContext,它既是依赖注入的"聚合入口",又不会把全局服务重复注册一遍。
生命周期管理:登录 → 游玩 → 退出
推荐把上下文生命周期与账号流程绑定:
- 游戏启动:
ApplicationContext自动创建,注册全局基础服务(绑定、本地化、日志、窗口管理等); - 玩家登录:
new PlayerContext(username),注册背包、邮件等玩家私有服务; - 游玩过程:业务代码统一通过上下文
GetService<T>()取服务,不直接new全局依赖; - 退出/切换账号:
playerContext.Dispose(),玩家级服务全部释放,全局服务保持不变。
常见坑与注意事项
- 服务必须实现
IDisposable才能被自动释放。Context.Dispose()只释放内部容器和已注册的可释放服务,普通对象需自行清理; - 不要重复注册相同类型/名称,会直接抛异常中断启动流程,适合暴露配置错误;
- 编辑器反复按播放时,
Context会在BeforeSceneLoad自动清理旧上下文,无需手动处理; - 自己扩展上下文(如副本上下文)时,
Context构造函数传null容器即可,内部会自动创建ServiceContainer; - 属性存取用
Set/Get(name),支持cascade参数决定是否向上查找,注意泛型转换不匹配会抛InvalidCastException。
更多扩展玩法(比如为 MMO 副本创建专属上下文)可阅读官方文档:docs/LoxodonFramework.md 中的"上下文(Context)"章节。
相关资源
- 上下文实现:Context.cs
- 应用上下文:ApplicationContext.cs
- 玩家上下文:PlayerContext.cs
- 服务容器实现:ServiceContainer.cs
- 服务接口定义:IServiceContainer.cs
【免费下载链接】loxodon-frameworkLoxodonFramework是一个轻量级的MVVM(Model-View-ViewModel)框架,它是专门为Unity3D游戏开发设计的,参考了WPF和Android的MVVM设计,它提供了视图和视图模型的数据绑定、本地化、一个简单的对象容器、配置文件组件、线程工具组件、应用上下文和玩家上下文,异步线程和协程的任务组件等基本组件,同时还提供了一个UI视图的框架。所有代码都基于面向对象面向接口的思路设计,几乎所有功能都可以自定义。而且在数据绑定部分进行了性能优化,避免值类型装箱拆箱,最小化垃圾回收的开销,使用动态委托/静态织入技术确保数据绑定和直接调用有相当的性能,0GC更新UI视图等等,它支持绑定到UGUI、UIToolkit和FairyGUI控件,同时也很容易扩展对其他UI控件的支持。此外,它已经在项目中得到验证(UWA评分SSS级,可在战斗中完全关闭GC,在6、7前手机都保证60FPS),性能优越,稳定可靠,架构清晰,可灵活扩展。 我们希望它能够帮助您更快、更轻松地开发游戏。 本框架使用C#语言开发,同时也支持使用XLua或者ILRuntime来开发,如果项目需要热更新,那么只要安装了XLua或者ILRuntime插件,则可以完全使用Lua或者ILRuntime来开发游戏。对于新立项的项目,建议使用HybridCLR来做热更新。 这个插件兼容 MacOSX,Windows,Linux,UWP,IOS and Android,WebGL等等,并且完全开源。项目地址: https://gitcode.com/vovgou/loxodon-framework
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考