Core源码依赖注入
Posted qixinbo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Core源码依赖注入相关的知识,希望对你有一定的参考价值。
依赖注入的源码是Microsoft.Extensions.DependencyInjection命名空间下的,项目结构比较复杂,本文先从先从简单的实现开始,一起了解下依赖注入最基础的实现
最基础的依赖注入
依赖注入容器
public class Cat { /// <summary> /// 线程安全的集合去保存所有的类型 /// </summary> private ConcurrentDictionary<Type, Type> typeMapping = new ConcurrentDictionary<Type, Type>(); //注册到容器中 public void Register(Type from, Type to) { typeMapping[from] = to; } //这个是核心方法 public object GetService(Type serviceType) { #region 构造函数注入 Type type; if (!typeMapping.TryGetValue(serviceType, out type)) { type = serviceType; } if (type.IsInterface || type.IsAbstract) { return null; } //获取构造函数的基本信息 ConstructorInfo constructor = this.GetConstructor(type); if (null == constructor) { return null; } //这里递归的获取了所有需要的实例 object[] arguments = constructor.GetParameters().Select(p => GetService(p.ParameterType)).ToArray(); //根据获得的参数调用构造函数 得到所需对象service object service = constructor.Invoke(arguments); #endregion return service; } /// <summary> /// 获取对应类型的构造器 /// </summary> /// <param name="type"></param> /// <returns></returns> protected virtual ConstructorInfo GetConstructor(Type type) { ConstructorInfo[] constructors = type.GetConstructors(); //如果我们有标记了InjectionAttribute 那么就用标记了的构造器 return constructors.FirstOrDefault(c => c.GetCustomAttribute<InjectionAttribute>() != null) ?? constructors.FirstOrDefault(); } }
扩展方法
public static class CatExtensions { public static T GetService<T>(this Cat cat) { if (cat == null) { throw new ArgumentNullException("collection"); } return (T)cat.GetService(typeof(T)); } public static void Register<TService, TImplementation>(this Cat cat) { if (cat == null) { throw new ArgumentNullException("collection"); } cat.Register(typeof(TService), typeof(TImplementation)); } }
实际使用
public interface IFoo { } public interface IBar { } public class Bar : IBar { } public class Foo : IFoo { public IBar Bar { get; private set; } public Foo() { } [Injection] public Foo(IBar bar) { this.Bar = bar; } } main方法 Cat cat = new Cat(); cat.Register<IFoo, Foo>(); cat.Register<IBar, Bar>(); IFoo service = cat.GetService<IFoo>(); Foo foo = (Foo)service; Console.WriteLine("cat.GetService<IFoo>(): {0}", service); Console.WriteLine("cat.GetService<IFoo>().Bar: {0}", foo.Bar);
这里我们通过public class InjectionAttribute : Attribute { } 标记需要注入的构造函数,然后我们简单的容器就会根据特性去选择对应执行的构造方法。
带有实例生命周期管理的依赖注入
ServiceRegistry
使用ServiceRegistry类进行服务注册的基础单元,我们将针对同一个服务类型(ServiceType属性相同)的多个ServiceRegistry组成一个链表,作为相邻节点的两个ServiceRegistry对象通过Next属性关联起来。我们为ServiceRegistry定义了一个AsEnumerable方法是它返回由当前以及后续节点组成的ServiceRegistry集合。
public enum Lifetime { Singlelton, Self, Transient } public class ServiceRegistry { public Type ServiceType { get; } public Lifetime Lifetime { get; } /// <summary> /// core的依赖注入还有实例模式,这里只有工厂模式做展示 /// </summary> public Func<Cat, Type[], object> Factory { get; } /// <summary> /// 同一个服务类型(ServiceType属性相同)的多个ServiceRegistry组成一个链表 /// </summary> internal ServiceRegistry Next { get; set; } public ServiceRegistry(Type serviceType, Lifetime lifetime, Func<Cat, Type[], object> factory) { ServiceType = serviceType; Lifetime = lifetime; Factory = factory; } public IEnumerable<ServiceRegistry> AsEnumerable() { var list = new List<ServiceRegistry>(); for (var self = this; self != null; self = self.Next) { list.Add(self); } return list; } }
主容器Cat
public class Cat : IServiceProvider, IDisposable { internal Cat _root; /// <summary> /// 类型注册到容器中时候,用来存储的集合 /// </summary> internal ConcurrentDictionary<Type, ServiceRegistry> _registries; /// <summary> /// 获取类型实例的集合 /// </summary> private ConcurrentDictionary<ServiceRegistry, object> _services; private ConcurrentBag<IDisposable> _disposables; /// <summary> /// Dispose()时候设置为true /// </summary> private volatile bool _disposed; /// <summary> /// 根容器的构造函数 /// </summary> public Cat() { _registries = new ConcurrentDictionary<Type, ServiceRegistry>(); _root = this; _services = new ConcurrentDictionary<ServiceRegistry, object>(); _disposables = new ConcurrentBag<IDisposable>(); } /// <summary> /// 创建子容器的构造函数 /// </summary> /// <param name="parent"></param> internal Cat(Cat parent) { _root = parent._root; _registries = _root._registries; _services = new ConcurrentDictionary<ServiceRegistry, object>(); _disposables = new ConcurrentBag<IDisposable>(); } public Cat Register(ServiceRegistry registry) { EnsureNotDisposed(); //判断是否有同类型的注册 if (_registries.TryGetValue(registry.ServiceType, out var existing)) { _registries[registry.ServiceType] = registry; registry.Next = existing; } else { _registries[registry.ServiceType] = registry; } return this; } /// <summary> /// 如果没注册过类型,会返回null /// </summary> /// <param name="serviceType"></param> /// <returns></returns> public object GetService(Type serviceType) { EnsureNotDisposed(); if (serviceType == typeof(Cat)) { return this; } ServiceRegistry registry; if (serviceType.IsGenericType && serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { var elementType = serviceType.GetGenericArguments()[0]; if (!_registries.TryGetValue(elementType, out registry)) { //没有就直接创建 return Array.CreateInstance(elementType, 0); } var registries = registry.AsEnumerable(); object[] services = registries.Select(it => GetServiceCore(it, new Type[0])).ToArray(); //创建一个数组,然后把所有注册到容器中的工厂方法的实例返回 Array array = Array.CreateInstance(elementType, services.Length); services.CopyTo(array, 0); return array; } if (serviceType.IsGenericType && !_registries.ContainsKey(serviceType)) { var definition = serviceType.GetGenericTypeDefinition(); return _registries.TryGetValue(definition, out registry) //泛型需要获取对应类型参数 ? GetServiceCore(registry, serviceType.GetGenericArguments()) : null; } return _registries.TryGetValue(serviceType, out registry) ? GetServiceCore(registry, new Type[0]) : null; } /// <summary> /// 实际进行实例创造的方法 /// </summary> /// <param name="registry"></param> /// <param name="genericArguments"></param> /// <returns></returns> private object GetServiceCore(ServiceRegistry registry, Type[] genericArguments) { var serviceType = registry.ServiceType; //方法内部的方法,我还真的很少这么写。 object GetOrCreate(ConcurrentDictionary<ServiceRegistry, object> services, ConcurrentBag<IDisposable> disposables) { if (services.TryGetValue(registry, out var service)) { return service; } service = registry.Factory(this, genericArguments); services[registry] = service; var disposable = service as IDisposable; if (null != disposable) { disposables.Add(disposable); } return service; } switch (registry.Lifetime) { case Lifetime.Singlelton: return GetOrCreate(_root._services, _root._disposables); case Lifetime.Self: return GetOrCreate(_services, _disposables); default: //如果是Transient类型,直接创建实例,然后判断是否是IDisposable,如果是加入IDisposable数组 //会在容器Disposable时候,遍历Disposable { var service = registry.Factory(this, genericArguments); var disposable = service as IDisposable; if (null != disposable) { _disposables.Add(disposable); } return service; } } } public void Dispose() { _disposed = true; foreach(var disposable in _disposables) { disposable.Dispose(); } while (!_disposables.IsEmpty) { _disposables.TryTake(out _); } _services.Clear(); } private void EnsureNotDisposed() { if (_disposed) { throw new ObjectDisposedException("Cat"); } } }
主容器的扩展方法
public static class CatExtensions { public static IEnumerable<T> GetServices<T>(this Cat cat) => cat.GetService<IEnumerable<T>>(); public static T GetService<T>(this Cat cat) => (T)cat.GetService(typeof(T)); public static bool HasRegistry<T>(this Cat cat) => cat.HasRegistry(typeof(T)); public static bool HasRegistry(this Cat cat, Type serviceType) => cat._root._registries.ContainsKey(serviceType); public static Cat Register(this Cat cat, Type from, Type to, Lifetime lifetime) { Func<Cat, Type[], object> factory = (x, arguments) => Create(x, to, arguments); cat.Register(new ServiceRegistry(from, lifetime, factory)); return cat; } public static Cat Register<TFrom, TTo>(this Cat cat, Lifetime lifetime) where TTo : TFrom { Func<Cat, Type[], object> factory = (_, arguments) => Create(_, typeof(TTo), arguments); cat.Register(new ServiceRegistry(typeof(TFrom), lifetime, factory)); return cat; } public static Cat Register<TServiceType>(this Cat cat, TServiceType instance) { Func<Cat, Type[], object> factory = (_, arguments) => instance; cat.Register(new ServiceRegistry(typeof(TServiceType), Lifetime.Singlelton, factory)); return cat; } public static Cat Register<TServiceType>(this Cat cat, Func<Cat, TServiceType> factory, Lifetime lifetime) { cat.Register(new ServiceRegistry(typeof(TServiceType), lifetime, (_, arguments) => factory(_))); return cat; } public static Cat CreateChild(this Cat cat) => new Cat(cat); private static object Create(Cat cat, Type type, Type[] genericArguments) { if (genericArguments.Length > 0)//是泛型的情况下 { //生成泛型类型 type = type.MakeGenericType(genericArguments); } var constructors = type.GetConstructors(); if (constructors.Length == 0)//没有构造函数的情况下 { throw new InvalidOperationException($"Cannot create the instance of {type} which does not have an public constructor."); } var constructor = constructors.FirstOrDefault(it => it.GetCustomAttributes(false).OfType<InjectionAttribute>().Any()); //空的时候用第一个 constructor = constructor ?? constructors.First(); var parameters = constructor.GetParameters(); if (parameters.Length == 0) { return Activator.CreateInstance(type); } var arguments = new object[parameters.Length]; //递归调用所有的parameters for (int index = 0; index < arguments.Length; index++) { var parameter = parameters[index]; var parameterType = parameter.ParameterType; if (cat.HasRegistry(parameterType)) { arguments[index] = cat.GetService(parameterType); } else if (parameter.HasDefaultValue) { arguments[index] = parameter.DefaultValue; } else//没有注册也没有默认的情况下,会抛出异常 { throw new InvalidOperationException($"Cannot create the instance of {type} whose constructor has non-registered parameter type(s)"); } } return Activator.CreateInstance(type, arguments); } }
Core依赖注入
CORE框架的依赖注入实现肯定比我们以上的实现复杂很多,他里面有实例的生命周期管理,ServiceProvider树等。
不过最基本的体系在我们上面的例子中都已经有介绍。
本文参考Artech大神的依赖注入文章和core源码。
以上是关于Core源码依赖注入的主要内容,如果未能解决你的问题,请参考以下文章
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段