zoukankan      html  css  js  c++  java
  • ABP 源码分析汇总之 AutoMapper

    AutoMapper 是一个对象映射工具,

    安装时只需要安装 如下即可:

    有关于它的介绍,参考官网:http://automapper.org/

    AutoMapper使用比较简单,还是直奔主题,看一下ABP是如何使用它的:

    首先Abp使用AutoMapper专门写的了一个模块Abp.AutoMapper,如下:

    跟其它模块一样,有一个继承自AbpModule的AbpAutoMapperModule类。

    在ABP自动生成的项目中,是在应用层依赖这个模块,从而对AutoMapper进行了初始化的配置:

        [DependsOn(typeof(AuditCoreModule), typeof(AbpAutoMapperModule))]  //这里
        public class AuditApplicationModule : AbpModule
        {
            public override void PreInitialize()
            {
            }
    
            public override void Initialize()
            {
                IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
            }
        }

    在AbpAutoMapperModule类中,我们看到这句:

    public override void PreInitialize()
            {
                IocManager.Register<IAbpAutoMapperConfiguration, AbpAutoMapperConfiguration>();
    
                Configuration.ReplaceService<ObjectMapping.IObjectMapper, AutoMapperObjectMapper>();//这句
    
                Configuration.Modules.AbpAutoMapper().Configurators.Add(CreateCoreMappings);
            }

    原来只要实现了IObjectMapper的对象映射工具,可以在abp项目中使用。

    再来看看,模块是如何创建映射配置的,CreateMappings方法调用FindAndAutoMapTypes()

    [DependsOn(typeof(AbpKernelModule))]
        public class AbpAutoMapperModule : AbpModule
        {
            private readonly ITypeFinder _typeFinder;
    
            private static volatile bool _createdMappingsBefore;
            private static readonly object SyncObj = new object();
            
            public AbpAutoMapperModule(ITypeFinder typeFinder)
            {
                _typeFinder = typeFinder;
            }
    public override void PostInitialize()
            {
                CreateMappings();
            }
    
            private void CreateMappings()
            {
                lock (SyncObj)
                {
                    Action<IMapperConfigurationExpression> configurer = configuration =>
                    {
                        FindAndAutoMapTypes(configuration);
                        foreach (var configurator in Configuration.Modules.AbpAutoMapper().Configurators)
                        {
                            configurator(configuration);
                        }
                    };
    
                    if (Configuration.Modules.AbpAutoMapper().UseStaticMapper)
                    {
                        //We should prevent duplicate mapping in an application, since Mapper is static.
                        if (!_createdMappingsBefore)
                        {
                            Mapper.Initialize(configurer);
                            _createdMappingsBefore = true;
                        }
    
                        IocManager.IocContainer.Register(
                            Component.For<IMapper>().Instance(Mapper.Instance).LifestyleSingleton()
                        );
                    }
                    else
                    {
                        var config = new MapperConfiguration(configurer);
                        IocManager.IocContainer.Register(
                            Component.For<IMapper>().Instance(config.CreateMapper()).LifestyleSingleton()
                        );
                    }
                }
            }
    
            private void FindAndAutoMapTypes(IMapperConfigurationExpression configuration)
            {
                var types = _typeFinder.Find(type =>
                    {
                        var typeInfo = type.GetTypeInfo();
                        return typeInfo.IsDefined(typeof(AutoMapAttribute)) ||
                               typeInfo.IsDefined(typeof(AutoMapFromAttribute)) ||
                               typeInfo.IsDefined(typeof(AutoMapToAttribute));
                    }
                );
    
                Logger.DebugFormat("Found {0} classes define auto mapping attributes", types.Length);
    
                foreach (var type in types)
                {
                    Logger.Debug(type.FullName);
                    configuration.CreateAutoAttributeMaps(type);
                }
            }
    
        }

    FindAndAutoMapTypes方法中_typeFinder.Find(),看名字就知道是根据里面的条件,找到符合条件的类型。看一下源码,它是如何找的,

     public AbpAutoMapperModule(ITypeFinder typeFinder)
            {
                _typeFinder = typeFinder;
            }

    typeFinder是接口,那它默认实现就是TypeFinder,我们在源码中很快找到了它:

        public class TypeFinder : ITypeFinder
        {public TypeFinder(IAssemblyFinder assemblyFinder)
            {
                _assemblyFinder = assemblyFinder;
                Logger = NullLogger.Instance;
            }
    
            public Type[] Find(Func<Type, bool> predicate)
            {
                return GetAllTypes().Where(predicate).ToArray();
            }
    private Type[] GetAllTypes()
            {
                if (_types == null)
                {
                    lock (_syncObj)
                    {
                        if (_types == null)
                        {
                            _types = CreateTypeList().ToArray();
                        }
                    }
                }
    
                return _types;
            }
    
            private List<Type> CreateTypeList()
            {
                var allTypes = new List<Type>();
    
                var assemblies = _assemblyFinder.GetAllAssemblies().Distinct();
    
                foreach (var assembly in assemblies)
                {
                    try
                    {
                        Type[] typesInThisAssembly;
    
                        try
                        {
                            typesInThisAssembly = assembly.GetTypes();
                        }
                        catch (ReflectionTypeLoadException ex)
                        {
                            typesInThisAssembly = ex.Types;
                        }
    
                        if (typesInThisAssembly.IsNullOrEmpty())
                        {
                            continue;
                        }
    
                        allTypes.AddRange(typesInThisAssembly.Where(type => type != null));
                    }
                    catch (Exception ex)
                    {
                        Logger.Warn(ex.ToString(), ex);
                    }
                }
    
                return allTypes;
            }
        }

    可以看到_assemblyFinder.GetAllAssemblies().Distinct();

    通过_assemblyFinder 是接口IAssemblyFinder,那它的实现是谁呢,看下面的代码。 这里是castle Windsor实现注册的方式之一。

    internal class AbpCoreInstaller : IWindsorInstaller
        {
            public void Install(IWindsorContainer container, IConfigurationStore store)
            {
                container.Register(
                    Component.For<IAbpModuleManager, AbpModuleManager>().ImplementedBy<AbpModuleManager>().LifestyleSingleton(),
                    Component.For<IAssemblyFinder, AbpAssemblyFinder>().ImplementedBy<AbpAssemblyFinder>().LifestyleSingleton(),
                    );
            }
        }

    我们看到AbpAssemblyFinder是我们要找到的类。

    public class AbpAssemblyFinder : IAssemblyFinder
        {
            private readonly IAbpModuleManager _moduleManager;
    
            public AbpAssemblyFinder(IAbpModuleManager moduleManager)
            {
                _moduleManager = moduleManager;
            }
    
            public List<Assembly> GetAllAssemblies()
            {
                var assemblies = new List<Assembly>();
    
                foreach (var module in _moduleManager.Modules)
                {
                    assemblies.Add(module.Assembly);
                    assemblies.AddRange(module.Instance.GetAdditionalAssemblies());
                }
    
                return assemblies.Distinct().ToList();
            }
        }

    看到这里就可以知道,ABP是通过module来找到assemblies的。 我们可以 AbpModuleManager : IAbpModuleManager这个类得到所有的模块。

    得到assemblies之后,可以得到所有Type信息,再根据过滤条件,得到autoMapper需要映射的类。

    再来看来这里的过滤条件:

     var types = _typeFinder.Find(type =>
                    {
                        var typeInfo = type.GetTypeInfo();
                        return typeInfo.IsDefined(typeof(AutoMapAttribute)) ||
                               typeInfo.IsDefined(typeof(AutoMapFromAttribute)) ||
                               typeInfo.IsDefined(typeof(AutoMapToAttribute));
                    }
                );

    三个Attribute. AutoMapAttribute, AutoMapFromAttribute, AutoMapToAttribute,通过名称可以知道它们的用途。

    此外,ABP还给我们提供了一个有用的扩展AutoMapExtensions,使用起来更加方便

    public static class AutoMapExtensions
        {
            /// <summary>
            /// Converts an object to another using AutoMapper library. Creates a new object of <typeparamref name="TDestination"/>.
            /// There must be a mapping between objects before calling this method.
            /// </summary>
            /// <typeparam name="TDestination">Type of the destination object</typeparam>
            /// <param name="source">Source object</param>
            public static TDestination MapTo<TDestination>(this object source)
            {
                return Mapper.Map<TDestination>(source);
            }
    
            /// <summary>
            /// Execute a mapping from the source object to the existing destination object
            /// There must be a mapping between objects before calling this method.
            /// </summary>
            /// <typeparam name="TSource">Source type</typeparam>
            /// <typeparam name="TDestination">Destination type</typeparam>
            /// <param name="source">Source object</param>
            /// <param name="destination">Destination object</param>
            /// <returns></returns>
            public static TDestination MapTo<TSource, TDestination>(this TSource source, TDestination destination)
            {
                return Mapper.Map(source, destination);
            }
        }
  • 相关阅读:
    用C++实现从键盘输入两个数a和b,求两数中的最大值
    MongoDB学习笔记-1
    linux 配置ip地址
    linux 配置jdk 环境变量
    VMware Linux 共享文件夹 虚拟机无共享文件解决方法
    数据库动态参数
    js
    js分页
    mysql存储过程
    webconfig 中配置上传文件大小
  • 原文地址:https://www.cnblogs.com/hankuikui/p/7778576.html
Copyright © 2011-2022 走看看