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已经成为标准化组件,功能更加强大,推荐使用。

作者:大石头 发布:2023-06-22 17:14:23 浏览:3,902)