在之前有些过一篇文章 《使用 DryIoc 替换 Abp 的 DI 框架》 ,在该文章里面我尝试通过以替换 IocManager
内部的 IContainer
来实现使用我们自己的 DI 框架。替换了之后我们基本上是可以正常使用了,不过仍然还存在有以下两个比较显著的问题。
- 拦截器功能无法正常使用,需要重复递归查找真实类型,消耗性能。
- 针对于通过
IServiceCollection.AddScoped()
方法添加的 Scoped 类型的解析存在问题。
下面我们就来针对于上述问题进行问题的分析与解决。
1. 问题 1
1.1 现象与原因
首先,来看一下问题 1 ,针对于问题 1 我在 Github 上面向作者请教了一下,造成嵌套注册的原因很简单。因为之所以我们解析的时候,原来的注册类型会解析出来代理类。
关于上述原因可以参考 DryIoc 的 Github 问题 #50 。
这是因为 DryIoc 是通过替换了原有注册类型的实现,而如果按照之前我们那篇文章的方法,每次注册事件被触发的时候就会针对注册类型嵌套一层代理类。这样如果某个类型有多个拦截器,这样就会造成一个类型嵌套的问题,在外层的拦截器被拦截到的时候无法获取到当前代理的真实类型。
1.2 思路与解决方法
解决思路也比较简单,就是我们在注册某个类型的时候,触发了拦截器注入事件。在这个时候,我们并不真正的执行代理类的一个操作。而是将需要代理的类型与它的拦截器类型通过字典存储起来,然后在类型完全注册完成之后,通过遍历这个字典,我们来一次性地为每一个注册类型进行拦截器代理。
思路清晰了,那么我们就可以编写代码来进行实现了,首先我们先为 IocManager 增加一个内部的字典,用于存储注册类-拦截器。
public class IocManager : IIocManager
{
// ... 其他代码
private readonly List<IConventionalDependencyRegistrar> _conventionalRegistrars;
private readonly ConcurrentDictionary<Type, List<Type>> _waitRegisterInterceptor;
// ... 其他代码
public IocManager()
{
_conventionalRegistrars = new List<IConventionalDependencyRegistrar>();
_waitRegisterInterceptor = new ConcurrentDictionary<Type, List<Type>>();
}
// ... 其他代码
}
之后我们需要开放两个方法用于为指定的注册类型添加对应的拦截器,而不是在类型注册事件被触发的时候直接生成代理类。
public interface IIocRegistrar
{
// ... 其他代码
/// <summary>
/// 为指定的类型添加拦截器
/// </summary>
/// <typeparam name="TService">注册类型</typeparam>
/// <typeparam name="TInterceptor">拦截器类型</typeparam>
void AddInterceptor<TService, TInterceptor>() where TInterceptor : IInterceptor;
/// <summary>
/// 为指定的类型添加拦截器
/// </summary>
/// <param name="serviceType">注册类型</param>
/// <param name="interceptor">拦截器类型</param>
void AddInterceptor(Type serviceType,Type interceptor);
// ... 其他代码
}
public class IocManager : IIocManager
{
// ... 其他代码
/// <inheritdoc />
public void AddInterceptor<TService, TInterceptor>() where TInterceptor : IInterceptor
{
AddInterceptor(typeof(TService),typeof(TInterceptor));
}
/// <inheritdoc />
public void AddInterceptor(Type serviceType, Type interceptorType)
{
if (_waitRegisterInterceptor.ContainsKey(serviceType))
{
var interceptors = _waitRegisterInterceptor[serviceType];
if (interceptors.Contains(interceptorType)) return;
_waitRegisterInterceptor[serviceType].Add(interceptorType);
}
else
{
_waitRegisterInterceptor.TryAdd(serviceType, new List<Type> {interceptorType});
}
}
// ... 其他代码
}
然后针对所有拦截器的监听事件进行替换,例如工作单元拦截器:
internal static class UnitOfWorkRegistrar
{
/// <summary>
/// 注册器初始化方法
/// </summary>
/// <param name="iocManager">IOC 管理器</param>
public static void Initialize(IIocManager iocManager)
{
// 事件监听处理
iocManager.RegisterTypeEventHandler += (manager, type, implementationType) =>
{
HandleTypesWithUnitOfWorkAttribute(iocManager,type,implementationType.GetTypeInfo());
HandleConventionalUnitOfWorkTypes(iocManager,type, implementationType.GetTypeInfo());
};
// 校验当前注册类型是否带有 UnitOfWork 特性,如果有则注入拦截器
private static void HandleTypesWithUnitOfWorkAttribute(IIocManager iocManager,Typ