NewLife组件是一个庞大的生态体系,提供了常见的各种组件,用搭积木的方式搭建起来整个体系。在用户选型的过程中,经常会出现只想要其中一部分功能而其它部分用第三方替代的情况。因此,设计了对象容器 ObjectContainer。各组件在设计过程中,如果遇到可插拔可替换的实现,一般抽象接口,把默认实现注册到对象容器里面去。
在NetCore时代,AspNetCore的DI依赖注入非常好用,但是遇到后台服务等非Web应用时,就不好使用DI。虽然也可以使用Worker项目模板,但是它会带来大量的DLL需要一起发布。此时,ObjectContainer就是最好的平滑替代方案。
同时,ObjectContainer支持.NET2.0/.NET4.0/.NET4.5以来的所有版本,保持跟NetCore时代一致的使用体验!
源码:https://github.com/NewLifeX/X/blob/master/NewLife.Core/Model/IObjectContainer.cs
视频:https://www.bilibili.com/video/BV1be41157kA
基本用法
对象容器本质上就是一个字典,服务类型(接口类型)为键,实现类型或具体实例为值。
IObjectContainer Register(Type serviceType, Type implementationType, Object instance); Object Resolve(Type serviceType);
这个字典比较简单,再次注册该服务类型时会覆盖前一次。
默认注册为单实例作用域,Resolve解析时返回注册进去的实例,如果没有就从实现类型中实例化一个。
对象容器内置有静态单一容器实例,可以通过 ObjectContainer.Current 直接使用。
/// <summary>当前容器</summary> public static IObjectContainer Current { get; set; } = new ObjectContainer();
ObjectContainer支持构造函数依赖注入,解析服务实例时,如果构造函数有参数,将会从容器池中解析获取。
对象容器支持更现代化的服务获取,通过 ObjectContainer.Provider 直接取得 IServiceProvider
/// <summary>当前容器提供者</summary> public static IServiceProvider Provider { get; set; } = new ServiceProvider(Current);
例如,在机器信息组件类中,我们借助对象容器保存单实例,随时可以解析取得:
var mi = Current ?? new MachineInfo(); mi.Init(); // 注册到对象容器 ObjectContainer.Current.AddSingleton(mi); /// <summary>从对象容器中获取一个已注册机器信息实例</summary> /// <returns></returns> public static MachineInfo Resolve() => ObjectContainer.Current.Resolve<MachineInfo>();
单实例注册
单实例注册扩展实现
IObjectContainer AddSingleton(this IObjectContainer container, Type serviceType, Type implementationType); IObjectContainer AddSingleton<TService, TImplementation>(this IObjectContainer container) where TService : class where TImplementation : class, TService; IObjectContainer AddSingleton(this IObjectContainer container, Type serviceType, Func<IServiceProvider, Object> factory); IObjectContainer AddSingleton<TService>(this IObjectContainer container, Func<IServiceProvider, Object> factory) where TService : class; IObjectContainer AddSingleton(this IObjectContainer container, Type serviceType, Object instance); IObjectContainer AddSingleton<TService>(this IObjectContainer container, TService instance) where TService : class; IObjectContainer TryAddSingleton(this IObjectContainer container, Type serviceType, Type implementationType); IObjectContainer TryAddSingleton<TService, TImplementation>(this IObjectContainer container); IObjectContainer TryAddSingleton<TService>(this IObjectContainer container, TService instance = null);
综上,单实例注册的扩展方式应用仅有,本质上都是向字典里面添加映射关系对。
单实例注册的映射,取出时直接取出注册进去的对象,如果该对象不存在就实例化一次然后永久保存。
范围注册
范围注册扩展实现
IObjectContainer AddScoped(this IObjectContainer container, Type serviceType, Type implementationType); IObjectContainer AddScoped<TService, TImplementation>(this IObjectContainer container); IObjectContainer AddScoped<TService>(this IObjectContainer container); IObjectContainer AddScoped(this IObjectContainer container, Type serviceType, Func<IServiceProvider, Object> factory); IObjectContainer AddScoped<TService>(this IObjectContainer container, Func<IServiceProvider, Object> factory); IObjectContainer TryAddScoped(this IObjectContainer container, Type serviceType, Type implementationType); IObjectContainer TryAddScoped<TService, TImplementation>(this IObjectContainer container); IObjectContainer TryAddScoped<TService>(this IObjectContainer container, TService instance = null);
瞬态注册
瞬态注册扩展实现
IObjectContainer AddTransient(this IObjectContainer container, Type serviceType, Type implementationType); IObjectContainer AddTransient<TService, TImplementation>(this IObjectContainer container) where TService : class where TImplementation : class, TService; IObjectContainer AddTransient<TService>(this IObjectContainer container) where TService : class; IObjectContainer AddTransient(this IObjectContainer container, Type serviceType, Func<IServiceProvider, Object> factory); IObjectContainer AddTransient<TService>(this IObjectContainer container, Func<IServiceProvider, Object> factory) where TService : class; IObjectContainer TryAddTransient(this IObjectContainer container, Type serviceType, Type implementationType); IObjectContainer TryAddTransient<TService, TImplementation>(this IObjectContainer container); IObjectContainer TryAddTransient<TService>(this IObjectContainer container, TService instance = null);
瞬态注册跟单实例注册差不多,不同之处在于,取出时总是实例化新的对象。
解析实例
对象容易的解析实例,借助 IServiceProvider能力
IServiceProvider BuildServiceProvider(this IObjectContainer container);
通过 BuildServiceProvider 方法,得到IServiceProvider,即可解析自己需要的对象实例。
ObjectContainer内置有单一容器的提供者实现,可以直接使用。
/// <summary>当前容器提供者</summary> public static IServiceProvider Provider { get; set; } = new ServiceProvider(Current);
例如,在Json反序列化中,经常需要创建目标类型的对象,此时目标类型可能是接口或者抽象类。JsonReader类中,就是通过对象容器解决。
private Object CreateObject(Type type) { var obj = ObjectContainer.Provider.GetService(type); if (obj != null) return obj; return type.CreateInstance(); }
在DefaultTracer类的静态构造函数中,注册了内置的一些类型
static DefaultTracer() { // 注册默认类型,便于Json反序列化时为接口属性创造实例 var ioc = ObjectContainer.Current; ioc.AddTransient<ITracer, DefaultTracer>(); ioc.AddTransient<ISpanBuilder, DefaultSpanBuilder>(); ioc.AddTransient<ISpan, DefaultSpan>(); }
因此,即使遇到以下类型的json字符串,JsonReader类也知道应该如果反序列化
/// <summary>跟踪片段构建器</summary> public interface ISpanBuilder { /// <summary>操作名</summary> String Name { get; set; } /// <summary>开始时间。Unix毫秒</summary> Int64 StartTime { get; set; } /// <summary>结束时间。Unix毫秒</summary> Int64 EndTime { get; set; } /// <summary>采样总数</summary> Int32 Total { get; } /// <summary>错误次数</summary> Int32 Errors { get; } /// <summary>总耗时。所有请求耗时累加,单位ms</summary> Int64 Cost { get; } /// <summary>最大耗时。单位ms</summary> Int32 MaxCost { get; } /// <summary>最小耗时。单位ms</summary> Int32 MinCost { get; } /// <summary>正常采样</summary> IList<ISpan> Samples { get; } /// <summary>异常采样</summary> IList<ISpan> ErrorSamples { get; } }
总结
2010年,早期ObjectContainer的引入,一定程度上加大了整个生态体系的复杂度,后来经历了一个削减的过程,插件式实现,更多附加在响应类的静态接口属性上。目前还在使用对象容器的地方相对较少。
随着.NETCore兴起,框架提供的DI已经成为标准化组件,功能更加强大,推荐使用。