zoukankan      html  css  js  c++  java
  • ABP文档笔记

    ABP框架 - 模块系统

    ABP框架 - 启动配置

    Module System

    Startup Configuration

    ABP源码分析三:ABP Module

    ABP源码分析四:Configuration

    基于Abp模块化、插件化的设计,开发人员可以将自定义的功能以模块的形式集成到项目中。通常地,一个程序集作为一个模块。如果你的应用是多个程序集,建议为每个程序集定义一个模块。

    模块的加载

    模块和插件

    插件:

    模块及插件的加载路线

     1. 扩展的HttpApplication对象(在Abp.Web项目中AbpWebApplication<TStartupModule> : HttpApplication)中有AbpBootstrapper成员

    AbpWebApplication的Application_Start方法:

    protected virtual void Application_Start(object sender, EventArgs e)
    {
        ThreadCultureSanitizer.Sanitize();
    
        AbpBootstrapper.Initialize();
    
        _webLocalizationConfiguration = AbpBootstrapper.IocManager.Resolve<IAbpWebLocalizationConfiguration>();
    }
    

     项目的Global文件中

    public class MvcApplication : AbpWebApplication<HKWEBWebModule>
    {
        protected override void Application_Start(object sender, EventArgs e)
        {
            AbpBootstrapper.IocManager.IocContainer.AddFacility<LoggingFacility>(
                f => f.UseAbpLog4Net().WithConfig("log4net.config")
            );
            //添加插件
            AbpBootstrapper.PlugInSources.AddFolder(@"C:MyPlugIns");
            AbpBootstrapper.PlugInSources.AddTypeList(typeof(MyPlugInModule));
            base.Application_Start(sender, e);
        }
    }

     AbpBootstrapper的Initialize方法

    public virtual void Initialize()
    {
        //实例化_logger
        ResolveLogger();
    
        try
        {
            //把Bootstrapper类自身加到容器里
            RegisterBootstrapper();
            IocManager.IocContainer.Install(new CoreInstaller());
    
            //将附加的插件加入队列
            IocManager.Resolve<PlugInManager>().PlugInSources.AddRange(PlugInSources);
    
            //StartupConfiguration.Modules,Settings,ServiceReplaceActions等
            IocManager.Resolve<StartupConfiguration>().Initialize();
    
            _moduleManager = IocManager.Resolve<ModuleManager>();
            //加载所有Module
            _moduleManager.Initialize(StartupModule);
            //对这些Module排序,之后依次执行所有模块的PreInitialize,Initialize,PostInitialize
            _moduleManager.StartModules();        
        }
        catch (Exception ex)
        {
            _logger.Fatal(ex.ToString(), ex);
            throw;
        }
    } 

    模块管理器的Initialize方法会加载所有依赖的模块,并通过模块类型上的Dependon属性按照依赖关系对它们进行顺序,同时也会加载AbpBootstrapper.PlugInSources中添加的插件(插件的添加 目前提供了两种实现)。

    AbpBootstrapper的Dispose方法,倒序释放各模块中加载的资源,在AbpWebApplication的Application_End方法中调用。

    public virtual void Dispose()
    {
        if (IsDisposed)
        {
            return;
        }
    
        IsDisposed = true;
    
        //倒序执行所有模块的Shutdown方法
        _moduleManager?.ShutdownModules();
    }
    

    模块管理器对模块的加载和释放

    AbpModule是一抽象类,所有的模块都是他的派生类。AbpModule提供PreInitialize,Initialize,PostInitialize,Shutdown四个无参无返回值方法,从名字上就可以看出AbpModule的生命周期被划成四部分,其中初始化被分成了三部分。

    ABP的模块查找基本就是对所有程序集进行遍历(IAssemblyFinder),再筛选出AbpModule的派生类(ITypeFinder)

    private List<Type> FindAllModuleTypes(out List<Type> plugInModuleTypes)
    {
        plugInModuleTypes = new List<Type>();
    
        var modules = AbpModule.FindDependedModuleTypesRecursivelyIncludingGivenModule(_modules.StartupModuleType);
        
        foreach (var plugInModuleType in _abpPlugInManager.PlugInSources.GetAllModules())
        {
            if (modules.AddIfNotContains(plugInModuleType))
            {
                plugInModuleTypes.Add(plugInModuleType);
            }
        }
    
        return modules;
    }

    按照依赖关系对它们排序,然后按顺序加载。

    public virtual void StartModules()
    {
        var sortedModules = _modules.GetSortedModuleListByDependency();
        sortedModules.ForEach(module => module.Instance.PreInitialize());
        sortedModules.ForEach(module => module.Instance.Initialize());
        sortedModules.ForEach(module => module.Instance.PostInitialize());
    }

    应用关闭时则倒序释放它们。

    public virtual void ShutdownModules()
    {
        Logger.Debug("Shutting down has been started");
    
        var sortedModules = _modules.GetSortedModuleListByDependency();
        sortedModules.Reverse();
        sortedModules.ForEach(sm => sm.Instance.Shutdown());
    
        Logger.Debug("Shutting down completed.");
    }
    

    所有AbpModule的派生类都被创建为单例

    private void RegisterModules(ICollection<Type> moduleTypes)
    {
        foreach (var moduleType in moduleTypes)
        {
            _iocManager.RegisterIfNot(moduleType);
        }
    }
    
    public static bool RegisterIfNot(this IIocRegistrar iocRegistrar, Type type, DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton)
    {
        if (iocRegistrar.IsRegistered(type))
        {
            return false;
        }
    
        iocRegistrar.Register(type, lifeStyle);
        return true;
    }
    

      而IocManager 和Configuration 也是单例,所以所以模块共享Ioc容器和配置信息。

    private void CreateModules(ICollection<Type> moduleTypes, List<Type> plugInModuleTypes)
    {
        foreach (var moduleType in moduleTypes)
        {
            var moduleObject = _iocManager.Resolve(moduleType) as AbpModule;
            if (moduleObject == null)
            {
                throw new AbpInitializationException("This type is not an ABP module: " + moduleType.AssemblyQualifiedName);
            }
    
            moduleObject.IocManager = _iocManager;
            moduleObject.Configuration = _iocManager.Resolve<IAbpStartupConfiguration>();
    
            var moduleInfo = new AbpModuleInfo(moduleType, moduleObject, plugInModuleTypes.Contains(moduleType));
    
            _modules.Add(moduleInfo);
    
            if (moduleType == _modules.StartupModuleType)
            {
                StartupModule = moduleInfo;
            }
    
            Logger.DebugFormat("Loaded module: " + moduleType.AssemblyQualifiedName);
        }
    }

    Configuration的加载

    模块在初始化时往往需要定义一些初始的变量或参数。ABP通过AbpStartupConfiguration,Castle的依赖注入,Dictionary对象和扩展方法很巧妙的实现了配置中心化。

    AbpStartupConfiguration中包含着Setting、Navigation、Location、EventBus、Feature等等核心模块的配置信息的引用,同时提供了一个IModuleConfigurations 类型的成员用于后期模块的配置扩展。

      在AbpBootstrapper的Initialize方法中可以看到它的实例化操作。

    配置中心的扩展

    定义模块的配置

    namespace Mt.Web.Configuration
    {
        public interface IAbpWebModuleConfiguration
        {
            IAbpAntiForgeryWebConfiguration AntiForgery { get; }
    
            IAbpWebLocalizationConfiguration Localization { get; }
        }
    
        public class AbpWebModuleConfiguration : IAbpWebModuleConfiguration
        {
            public IAbpAntiForgeryWebConfiguration AntiForgery { get; }
            public IAbpWebLocalizationConfiguration Localization { get; }
    
            public AbpWebModuleConfiguration(
                IAbpAntiForgeryWebConfiguration antiForgery, 
                IAbpWebLocalizationConfiguration localization)
            {
                AntiForgery = antiForgery;
                Localization = localization;
            }
        }
    }

    扩展 IAbpStartupConfiguration(提供一个对自定义配置的快捷访问)

    利用字典的特性,通过一个扩展方法用于添加配置信息,configurations.AbpConfiguration就是IAbpStartupConfiguration。

    public static class AbpWebConfigurationExtensions
    {
        /// <summary>
        /// Used to configure ABP Web module.
        /// </summary>
        public static IAbpWebModuleConfiguration AbpWeb(this IModuleConfigurations configurations)
        {
            return configurations.AbpConfiguration.Get<IAbpWebModuleConfiguration>();
        }
    }
    

     原理: 

    internal class AbpStartupConfiguration : DictionaryBasedConfig, IAbpStartupConfiguration
    {
        /// <summary>
        /// Reference to the IocManager.
        /// </summary>
        public IIocManager IocManager { get; }
    
        /// <summary>
        /// Used to configure modules.
        /// Modules can write extension methods to <see cref="ModuleConfigurations"/> to add module specific configurations.
        /// </summary>
        public IModuleConfigurations Modules { get; private set; }
    
        public T Get<T>()
        {
            return GetOrCreate(typeof(T).FullName, () => IocManager.Resolve<T>());
        }
    	
    	//……
    }
    

      

    public class DictionaryBasedConfig : IDictionaryBasedConfig
    {
        /// <summary>
        /// Dictionary of custom configuration.
        /// </summary>
        protected Dictionary<string, object> CustomSettings { get; private set; }
    
        /// <summary>
        /// Gets a configuration object with given name.
        /// </summary>
        public T GetOrCreate<T>(string name, Func<T> creator)
        {
            var value = Get(name);
            if (value == null)
            {
                value = creator();
                Set(name, value);
            }
            return (T) value;
        }
    	
    	//……
    }

    注册本模块的配置信息

    在AbpModule中有Configurations属性(IAbpStartupConfiguration,单例),

    在AbpModule的PreInitialize(预初始化事件)中会将本模块的配置信息封装注册到IoC容器。

    同时预初始化事件中还可以调整自己或其他模块的配置信息,以及通过ReplaceService方法替换内置服务(模块预初始化方法是按依赖关系顺序被执行,所以最后有效的是最后一次替换后的结果

    namespace Mt.Web
    {
        [DependsOn(typeof(AbpWebCommonModule))]    
        public class AbpWebModule : AbpModule
        {
            /// <inheritdoc/>
            public override void PreInitialize()
            {
                //注册一些不能依据约定自动注册的服务。
                IocManager.Register<IAbpAntiForgeryWebConfiguration, AbpAntiForgeryWebConfiguration>();
                IocManager.Register<IAbpWebLocalizationConfiguration, AbpWebLocalizationConfiguration>();
                IocManager.Register<IAbpWebModuleConfiguration, AbpWebModuleConfiguration>();
                //替换服务
                Configuration.ReplaceService<IPrincipalAccessor, HttpContextPrincipalAccessor>(DependencyLifeStyle.Transient);
                Configuration.ReplaceService<IClientInfoProvider, WebClientInfoProvider>(DependencyLifeStyle.Transient);
                //修改内置配置 
                Configuration.MultiTenancy.Resolvers.Add<DomainTenantResolveContributer>();
                Configuration.MultiTenancy.Resolvers.Add<HttpHeaderTenantResolveContributer>();
                Configuration.MultiTenancy.Resolvers.Add<HttpCookieTenantResolveContributer>();
    
                AddIgnoredTypes();
    
                //修改扩展配置
                Configuration.Modules.AbpWeb().Localization.CookieName = "Abp.Localization.CultureName";
            }
    
            /// <inheritdoc/>
            public override void Initialize()
            {
                IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());            
            }
    
            private void AddIgnoredTypes()
            {
                var ignoredTypes = new[]
                {
                    typeof(HttpPostedFileBase),
                    typeof(IEnumerable<HttpPostedFileBase>),
                    typeof(HttpPostedFileWrapper),
                    typeof(IEnumerable<HttpPostedFileWrapper>)
                };
                
                foreach (var ignoredType in ignoredTypes)
                {
                    Configuration.Auditing.IgnoredTypes.AddIfNotContains(ignoredType);
                    Configuration.Validation.IgnoredTypes.AddIfNotContains(ignoredType);
                }
            }
        }
    }    
    

    使用配置信息 

    配置都是以单例的方式注册的,所以在各模块中,以及在任何使用它的服务里,修改和读取的都是同一组配置数据。

    public class MyService : ITransientDependency
    {
        private readonly IAbpWebModuleConfiguration _configuration;
    
        public MyService(IAbpWebModuleConfiguration configuration)
        {
            _configuration = configuration;
        }
    
        public void DoIt()
        {
            if (_configuration.Localization.CookieName = "Abp.Localization.CultureName")
            {
                //...
            }
        }
    }
    

      

      

      

  • 相关阅读:
    Let和Const的使用
    Spring框架学习10——JDBC Template 实现数据库操作
    python 学习
    delphi
    mysql 客户端连接报错Illegal mix of collations for operation
    tnsping 不通
    orm总结
    other
    resultset 查询时返回多个相同值
    vlan 知识学习
  • 原文地址:https://www.cnblogs.com/wj033/p/6133595.html
Copyright © 2011-2022 走看看