zoukankan      html  css  js  c++  java
  • ABP模块配置

    介绍

    我们知道ABP中模块的配置都是通过模块的Configuration属性来设置的。例如在模块的生命周期方法中可以进行一系列的配置 审计 MQ Redis....也可以替换一些ABP默认配置
    通常我们的用户模块(自定义模块)都会继承自AbpModule,它是ABP所有模块的基类.也是个抽象类.

    public abstract class AbpModule
    {
        protected internal IIocManager IocManager { get; internal set; }
    
        protected internal IAbpStartupConfiguration Configuration { get; internal set; }
        // 其他代码 
    }
    

    这里的两个属性分别是IIocManager和IAbpStartupConfiguration,所以我们的用户模块可以使用.
    IocManager已经研究过了,现在来看看IAbpStartupConfiguration,先看看类关系图
    IAbpStartupConfiguration
    可以看到ABP一系列的基础设施都在里面,授权 事件总线 等等.

    启动流程

    IAbpStartupConfiguration注册,初始化其实都是在ABPBootStrap的初始化方法中执行的.

    public virtual void Initialize()
    {
        // 其他代码
        try
        {
            // 注册了相关基础设施的配置
            IocManager.IocContainer.Install(new AbpCoreInstaller());
            IocManager.Resolve<AbpStartupConfiguration>().Initialize();
             // 相关模块方法
        }
    }
    

    可以看到首先已单例的形式注册了一些基础设施.然后从容器中取出AbpStartupConfiguration执行Initialize方法

    public void Initialize()
    {
        Localization = IocManager.Resolve<ILocalizationConfiguration>();
        Modules = IocManager.Resolve<IModuleConfigurations>();
        Features = IocManager.Resolve<IFeatureConfiguration>();
        Navigation = IocManager.Resolve<INavigationConfiguration>();
        Authorization = IocManager.Resolve<IAuthorizationConfiguration>();
        Validation = IocManager.Resolve<IValidationConfiguration>();
        Settings = IocManager.Resolve<ISettingsConfiguration>();
        UnitOfWork = IocManager.Resolve<IUnitOfWorkDefaultOptions>();
        EventBus = IocManager.Resolve<IEventBusConfiguration>();
        MultiTenancy = IocManager.Resolve<IMultiTenancyConfig>();
        Auditing = IocManager.Resolve<IAuditingConfiguration>();
        Caching = IocManager.Resolve<ICachingConfiguration>();
        BackgroundJobs = IocManager.Resolve<IBackgroundJobConfiguration>();
        Notifications = IocManager.Resolve<INotificationConfiguration>();
        EmbeddedResources = IocManager.Resolve<IEmbeddedResourcesConfiguration>();
        EntityHistory = IocManager.Resolve<IEntityHistoryConfiguration>();
    
        CustomConfigProviders = new List<ICustomConfigProvider>();
        ServiceReplaceActions = new Dictionary<Type, Action>();
    }
    

    主要是从容器中取出Configuration,为AbpStartupConfiguration对应的属性赋值.以及初始化工作.
    ServiceReplaceActions是一个键值对的集合,这是我们以后替换默认基础配置需要用到的.
    Ps:IAbpStartupConfiguration是ABPModule的一个属性,已依赖注入的方式早已经注入进容器,所以我们的自定义模块可以很方便的对一些基础设施做出配置.
    例如Configuration.Caching..... | Configuration.Auditing..... 等等

    自定义模块设置

    internal class AbpStartupConfiguration : DictionaryBasedConfig, IAbpStartupConfiguration
    

    可以看到我们的AbpStartupConfiguration还继承自DictionaryBasedConfig,这个类定义如下:

    namespace Abp.Configuration
    {
        /// <summary>
        /// Used to set/get custom configuration.
        /// </summary>
        public class DictionaryBasedConfig : IDictionaryBasedConfig
        {
            /// <summary>
            /// Dictionary of custom configuration.
            /// </summary>
            protected Dictionary<string, object> CustomSettings { get; private set; }
    
            /// <summary>
            /// Gets/sets a config value.
            /// Returns null if no config with given name.
            /// </summary>
            /// <param name="name">Name of the config</param>
            /// <returns>Value of the config</returns>
            public object this[string name]
            {
                get { return CustomSettings.GetOrDefault(name); }
                set { CustomSettings[name] = value; }
            }
    
            /// <summary>
            /// Constructor.
            /// </summary>
            protected DictionaryBasedConfig()
            {
                CustomSettings = new Dictionary<string, object>();
            }
    
            /// <summary>
            /// Gets a configuration value as a specific type.
            /// </summary>
            /// <param name="name">Name of the config</param>
            /// <typeparam name="T">Type of the config</typeparam>
            /// <returns>Value of the configuration or null if not found</returns>
            public T Get<T>(string name)
            {
                var value = this[name];
                return value == null
                    ? default(T)
                    : (T) Convert.ChangeType(value, typeof (T));
            }
    
            /// <summary>
            /// Used to set a string named configuration.
            /// If there is already a configuration with same <paramref name="name"/>, it's overwritten.
            /// </summary>
            /// <param name="name">Unique name of the configuration</param>
            /// <param name="value">Value of the configuration</param>
            public void Set<T>(string name, T value)
            {
                this[name] = value;
            }
    
            /// <summary>
            /// Gets a configuration object with given name.
            /// </summary>
            /// <param name="name">Unique name of the configuration</param>
            /// <returns>Value of the configuration or null if not found</returns>
            public object Get(string name)
            {
                return Get(name, null);
            }
    
            /// <summary>
            /// Gets a configuration object with given name.
            /// </summary>
            /// <param name="name">Unique name of the configuration</param>
            /// <param name="defaultValue">Default value of the object if can not found given configuration</param>
            /// <returns>Value of the configuration or null if not found</returns>
            public object Get(string name, object defaultValue)
            {
                var value = this[name];
                if (value == null)
                {
                    return defaultValue;
                }
    
                return this[name];
            }
    
            /// <summary>
            /// Gets a configuration object with given name.
            /// </summary>
            /// <typeparam name="T">Type of the object</typeparam>
            /// <param name="name">Unique name of the configuration</param>
            /// <param name="defaultValue">Default value of the object if can not found given configuration</param>
            /// <returns>Value of the configuration or null if not found</returns>
            public T Get<T>(string name, T defaultValue)
            {
                return (T)Get(name, (object)defaultValue);
            }
    
            /// <summary>
            /// Gets a configuration object with given name.
            /// </summary>
            /// <typeparam name="T">Type of the object</typeparam>
            /// <param name="name">Unique name of the configuration</param>
            /// <param name="creator">The function that will be called to create if given configuration is not found</param>
            /// <returns>Value of the configuration or null if not found</returns>
            public T GetOrCreate<T>(string name, Func<T> creator)
            {
                var value = Get(name);
                if (value == null)
                {
                    value = creator();
                    Set(name, value);
                }
                return (T) value;
            }
        }
    }
    

    这里维护了一个protected Dictionary<string, object> CustomSettings { get; private set; }字典,key是字符串类型,value是一个object. 用来存放配置类的,看上述代码可知,还有一些get方法。用来获取配置
    用的话也比较简单,只需要在模块的预初始化方法中向DI容器注册配置类即可.

    public override void PreInitialize()
    {
        // BlogWebCoreConfigration 里可以设置具体的配置,这里简略了.
       IocManager.Register(typeof(IBlogWebCoreConfigration), typeof(BlogWebCoreConfigration));
    }
    

    AbpStartupConfiguration有个public IModuleConfigurations Modules { get; private set; },这个接口主要是让我们加入自定义的配置

    public interface IModuleConfigurations
    {
        /// <summary>
       /// Gets the ABP configuration object.
       /// </summary>
      IAbpStartupConfiguration AbpConfiguration { get; }
    }
    

    所以我们只需要写个静态类用扩展方法即可

    public static class BlogWebCoreConfigrationExt
    {
       public static IBlogWebCoreConfigration BlogWebCoreModule(this IModuleConfigurations configuration)
       {
          return configuration.AbpConfiguration.Get<IBlogWebCoreConfigration>();
       }
    }
    

    随后我们即可在预初始化方法中 进行配置了
    例如;

    Configuration.Modules.BlogWebCoreModule().xxxx= true;
    

    自定义配置总流程就是
    1.创建一个模块配置类,写上你需要配置的东西
    2.创建一个IModuleConfigurations的扩展方法,用AbpConfiguration属性从容器中获取配置类
    3.在预初始化方法中调用静态方法即可

    替换ABP默认服务

    IAbpStartupConfiguration中提供了一个ReplaceService方法

    public void ReplaceService(Type type, Action replaceAction)
    {
        ServiceReplaceActions[type] = replaceAction;
    }
    

    作用就是像键值对集合中添加个Key和value,replaceAction是具体要怎么做.
    这个方法和我们平时看到的替换服务的方法不一样,我们猜测肯定有扩展方法,根据具体引用查看,

    public static void ReplaceService<TType, TImpl>(this IAbpStartupConfiguration configuration, DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton)
        where TType : class
        where TImpl : class, TType
    {
        configuration.ReplaceService(typeof(TType), () =>
        {
            configuration.IocManager.Register<TType, TImpl>(lifeStyle);
        });
    }
    

    果然没错,跟着引用找到了这个方法,这里就是调用了 上述方法,向容器中注册了服务。
    那么是什么时候执行注册的呢?
    既然它是个集合,还储存了注册的方法.那么我们直接跟着这个集合的引用找一下就可以了.
    最终找到是在AbpKernelModule的初始化方法中的执行的.

    public override void Initialize()
    {
        foreach (var replaceAction in ((AbpStartupConfiguration)Configuration).ServiceReplaceActions.Values)
        {
            replaceAction();
        }
        // 其他代码 略.
    }
    

    这里从AbpMoudel获取AbpStartupConfiguration并遍历它的value(向容器中注册组件action),并调用.
    也就是在这里完成了注册.之前也探索过Abp核心模块永远是一个执行初始化方法的,也就确保了我们自己的组件顺利替换

    那么问题来了,我们在哪里可以替换配置?

    先理一下,首先,执行替换配置服务的核心方法是在abp核心模块的Initialize方法(第一行)中执行的.
    执行完成,容器中就已经有了,那肯定是在abp核心模块执行Initialize方法前,我们调用Configuration.ReplaceService方法,将类型和action委托存入字典对象中
    之前也说过模块的生命周期执行方法顺序,先是执行所有模块的PreInitialize,然后执行所有模块的Initialize,最后执行PostInitialize
    所以很明显,我们需要在自定义模块中的PreInitialize中执行替换方法.

    public override void PreInitialize()
    {
        Configuration.ReplaceService<Ixxxxx, xxxx>(DependencyLifeStyle.Transient);
    }
    
  • 相关阅读:
    java截取字符串
    Integer
    Sql语句常用关键字
    mybatis三种传值方式
    mybatis中的#和$的区别
    374. Guess Number Higher or Lower
    278. First Bad Version
    69. Sqrt(x)
    35. Search Insert Position
    167. Two Sum II
  • 原文地址:https://www.cnblogs.com/zzqvq/p/10283694.html
Copyright © 2011-2022 走看看