StackExchange.Redis.Extensions.Core 源码解读之 Configuration用法

前言

  之前接触到Redis,然后选用了对StackExchange.Redis又一层封装的StackExchange.Redis.Extensions.Core类库。阅读源代码的过程中发现了他使用Configuration实现读取自定义配置的方法。特此学习并记录。在我们日常开发中,最常用的自定义配置读取方式莫过于如下两种方式,尤其是连接数据库。

           //读取appsetting
                var appSettingValue = ConfigurationManager.AppSettings["KEY"];
                //读取connectionstring
                var connectionValue = ConfigurationManager.ConnectionStrings["KEY"];

  而在使用这个类库的时候它的配置形式是这样的:

<configSections>
    <section name="redisCacheClient"
           type="StackExchange.Redis.Extensions.Core.Configuration.RedisCachingSectionHandler, StackExchange.Redis.Extensions.Core" />
  </configSections>

  <redisCacheClient allowAdmin="true" ssl="false" connectTimeout="5000" database="0" password="">
    <hosts>
      <add host="127.0.0.1" cachePort="6379"/>      <add host="127.0.0.1" cachePort="6380"/>  </hosts> </redisCacheClient>

  没错,就是自定义section,然后在读取section中详细的配置信息,如上述代码所示,sectionName=redisCacheClient,allowAdmin,ssl等都是它的配置信息。<hosts>节点比较特殊,它是一系列配置信息的集合。

代码解读

  先看一下自定义配置接口,里面就包含了 redisCacheClient中的各种属性定义

  

/// <summary>
    /// 自定义配置接口
    /// </summary>
    public interface IRedisCachingConfiguration
    {
        /// <summary>
        /// Redis Server的服务端口配置
        /// </summary>
        /// <value>
        /// IP地址或者服务器名称
        /// </value>
        RedisHostCollection RedisHosts { get; }

        /// <summary>
        /// The strategy to use when executing server wide commands
        /// </summary>
        ServerEnumerationStrategy ServerEnumerationStrategy { get; }

        /// <summary>
        /// 定义是否该连接可以使用管理员权限操作,比如flush database
        /// </summary>
        /// <value>
        ///   <c>true</c> 可以使用管理员权限; 否则, <c>false</c>.
        /// </value>
        bool AllowAdmin { get; }

        /// <summary>
        /// 是否SSL安全加密
        /// </summary>
        /// <value>
        ///   <c>true</c> if is secure; otherwise, <c>false</c>.
        /// </value>
        bool Ssl { get; }

        /// <summary>
        /// 连接超时时间
        /// </summary>
        int ConnectTimeout { get; }

        /// <summary>
        /// 没有服务可用的时候,不会创建新连接
        /// </summary>
        bool AbortOnConnectFail { get; }

        /// <summary>
        /// Database Id
        /// </summary>
        /// <value>
        /// database的ID,默认为0
        /// </value>
        int Database { get; }

        /// <summary>
        /// 密码
        /// </summary>
        string Password { get; }
    }

  我们看一下类的具体实现,首先要继承自定义的接口,还要继承ConfigurationSection,这样当我们取比如说 allowAdmin的值的时候可以在内部直接调用 this["allowAdmin"]取到值了。

  /// <summary>
    /// 继承自定义接口,并且继承ConfigurationSection<see cref="IRedisCachingConfiguration"/>
    /// </summary>
    public class RedisCachingSectionHandler : ConfigurationSection, IRedisCachingConfiguration
    {

        //这里就只拿allowAdmin举例,默认是string类型,那么我们就要根据自己的需求进行数据类型转换了。这里就把string类型转换为我们想要的bool类型
        [ConfigurationProperty("allowAdmin")]
        public bool AllowAdmin
        {
            get
            {

                bool result = false;
                var config = this["allowAdmin"];

                if (config != null)
                {
                    var value = config.ToString();

                    if (!string.IsNullOrEmpty(value))
                    {
                        if (bool.TryParse(value, out result))
                        {
                            return result;
                        }
                    }
                }

                return result;
            }
        }

       //其他代码    ...    .../// <summary>
        /// 读取配置信息,外部调用主方法
        /// </summary>
        /// <returns></returns>
        public static RedisCachingSectionHandler GetConfig()
        {
            return ConfigurationManager.GetSection("redisCacheClient") as RedisCachingSectionHandler;
        }
    }

  下面我们在看一下元素集合的使用,单节点RedisHost代码如下:

/// <summary>
    /// RedisHost的配置元素
    /// </summary>
    public class RedisHost : ConfigurationElement
    {
        /// <summary>
        /// Gets the Redis host.
        /// </summary>
        /// <value>
        ///获取host节点值
        /// </value>
        [ConfigurationProperty("host", IsRequired = true)]
        public string Host
        {
            get
            {
                return this["host"] as string;
            }
        }

        /// <summary>
        /// Gets the port.
        /// </summary>
        /// <value>
        /// 获取cachePort的值
        /// </value>
        [ConfigurationProperty("cachePort", IsRequired = true)]
        public int CachePort
        {
            get
            {
                var config = this["cachePort"];
                if (config != null)
                {
                    var value = config.ToString();

                    if (!string.IsNullOrEmpty(value))
                    {
                        int result;

                        if (int.TryParse(value, out result))
                        {
                            return result;
                        }
                    }
                }

                throw new Exception("Redis Cahe port must be number.");
            }
        }
    }

  还需要定义一个Collection将Hosts中的内容收集起来。类似List

/// <summary>
    /// Configuration Element Collection for <see cref="RedisHost"/>
    /// </summary>
    public class RedisHostCollection : ConfigurationElementCollection
    {
        /// <summary>
        /// Gets or sets the <see cref="RedisHost"/> at the specified index.
        /// </summary>
        /// <value>
        /// The <see cref="RedisHost"/>.
        /// </value>
        /// <param name="index">The index.</param>
        /// <returns></returns>
        public RedisHost this[int index]
        {
            //BaseGet,BaseRemoveAt,BaseAdd都是 ConfigurationElementCollection 中定义的方法
            get
            {
                //调用BaseGet方法获取节点信息
                return BaseGet(index) as RedisHost;
            }
            set
            {
                //设置的时候先删掉,在添加
                if (BaseGet(index) != null)
                {
                    BaseRemoveAt(index);
                }

                BaseAdd(index, value);
            }
        }

        /// <summary>
        ///此方法需要重写,返回一个新节点
        /// </summary>
        /// <returns></returns>
        protected override ConfigurationElement CreateNewElement()
        {
            return new RedisHost();
        }

        /// <summary>
        /// 重写此方法,获取元素key
        /// </summary>
        /// <param name="element">元素</param>
        /// <returns></returns>
        protected override object GetElementKey(ConfigurationElement element)
            //这里可以看到,这个key就是 Host:Port
            => $"{((RedisHost) element).Host}:{((RedisHost) element).CachePort}";
    }

  经过一层层的包装之后,Handler中后去Host的节点方法就很简单了。

/// <summary>
        /// The host of Redis Server
        /// </summary>
        /// <value>
        /// The ip or name
        /// </value>
        [ConfigurationProperty("hosts")]
        public RedisHostCollection RedisHosts
            => this["hosts"] as RedisHostCollection;

  我们运行程序读取一下试试:

         RedisCachingSectionHandler config = RedisCachingSectionHandler.GetConfig();
            Console.WriteLine("config中的allowAdmin:" + config.AllowAdmin);
            Console.WriteLine("config中的ssl:" + config.Ssl);
            Console.WriteLine("config中的password:" + config.Password);
            Console.WriteLine("config中的database:" + config.Database);
            Console.WriteLine();
            Console.WriteLine("读取Host信息如下:");
            foreach (RedisHost host in config.RedisHosts)
            {
                Console.WriteLine($"{host.Host}:{host.CachePort}");
            }
            Console.Read();

  运行结果:

  

  config中的信息已经正常读取到。那么我们可以用这种方式实现读取自己自定义的配置信息啦。当然,简单的配置还是直接用 <add key="key" value="value"/>

总结

  微软库已经给我们提供了太多的方法,在不知情的情况下我们往往会自己去实现。多看看开源代码对自己知识的提升还有有帮助的。这不,学会了这种配置方法,我们就可使用不仅仅ConfigurationManager这个类了。

时间: 2024-10-08 23:09:10

StackExchange.Redis.Extensions.Core 源码解读之 Configuration用法的相关文章

asp.net core源码飘香:Configuration组件(转)

简介: 这是一个基础组件,是一个统一的配置模型,配置可以来源于配置文件(json文件,xml文件,ini文件),内存对象,命令行参数,系统的环境变量又或者是你自己扩展的配置源,该组件将各个配置源的数据按统一的格式(IDictionary<string, string> Data)进行加载,进而对外提供调用接口. 不仅如此,有些配置源(如文件配置源)还可以在配置源的数据发生变化时进行重新加载(IDictionary<string, string> Data),而程序员随时可以判断是否

spring core源码解读之ASM4用户手册翻译

ASM动机: 程序的分析,生成,转换技术可以应用到许多场景: 1.程序分析,从简单的语法解析到完整的语义分析,可以应用在程序中找到潜在的bug,发现无用的代码,工程代码的逆向等等. 2.代码生成应用在各种编译器中:既包括传统的编译器也包括分布式编程的stub或者skeleton编译器,即时编译器等等. 3. 代码转换,可用于优化或混淆程序,向应用中插入测试或性能监控程序,面向切面编程等等. 这些技术可以用在任何编程语言,但或多或少容易依赖语言.在java 语言中,它们可以应用在源码中也可以应用在

spring core源码解读之ASM4用户手册翻译之一asm简介

第一章:ASM介绍 1.1 ASM动机: 程序的分析,生成,转换技术可以应用到许多场景: 1.程序分析,从简单的语法解析到完整的语义分析,可以应用在程序中找到潜在的bug,发现无用的代码,工程代码的逆向等等. 2.代码生成应用在各种编译器中:既包括传统的编译器也包括分布式编程的stub或者skeleton编译器,即时编译器等等. 3. 代码转换,可用于优化或混淆程序,向应用中插入测试或性能监控程序,面向切面编程等等. 这些技术可以用在任何编程语言,但或多或少容易依赖语言.在java 语言中,它们

asp.net core源码飘香:Configuration组件

简介: 这是一个基础组件,是一个统一的配置模型,配置可以来源于配置文件(json文件,xml文件,ini文件),内存对象,命令行参数,系统的环境变量又或者是你自己扩展的配置源,该组件将各个配置源的数据按统一的格式(IDictionary<string, string> Data)进行加载,进而对外提供调用接口. 不仅如此,有些配置源(如文件配置源)还可以在配置源的数据发生变化时进行重新加载(IDictionary<string, string> Data),而程序员随时可以判断是否

asp.net core源码飘香:Logging组件(转)

简介: 作为基础组件,日志组件被其他组件和中间件所使用,它提供了一个统一的编程模型,即不需要知道日志最终记录到哪里去,只需要调用它即可. 使用方法很简单,通过依赖注入ILogFactory(CreateLogger方法)或ILogger<T>对象,获取一个ILogger对象,然后通过ILogger的各种扩展方法(都是调用Log方法)记录不同级别的日志. 源码剖析: 总结: 日志组件其实就是工厂模式的应用,但进行了改进,LoggerFactory每次都返回一个Logger对象,而Logger对象

Redis内存管理的基石zmallc.c源码解读(附录):源码结构表

Redis内存管理的基石zmallc.c源码解读(一) Redis内存管理的基石zmallc.c源码解读(二) 前面两篇博文,细致地介绍了zmalloc.c文件的各个函数,不过大家要想深入学习Redis,还需要自己去看源码才是,我梳理了一下zmalloc.c文件的结构,为大家阅读源码提供便利. 全局变量 名称 类型 说明 used_memory static size_t Redis已用内存空间的大小 zmalloc_thread_safe static int 标识是否线程安全 used_me

Jfinal启动源码解读

本文对Jfinal的启动源码做解释说明. PS:Jfinal启动容器可基于Tomcat/Jetty等web容器启动,本文基于Jetty的启动方式做启动源码的解读和分析,tomcat类似. 入口  JFinalConfig的继承类的Main方法为入口,实例代码继承类为:DemoConfig,Main方法如下: public static void main(String[] args) { /** * 特别注意:Eclipse 之下建议的启动方式 */ JFinal.start("WebRoot&

solr源码解读(转)

solr源码解读(转)原文地址:http://blog.csdn.net/duck_genuine/article/details/6962624 配置 solr 对一个搜索请求的的流程 在solrconfig.xml会配置一个handler.配置了前置处理组件preParams,还有后置处理组件filterResult,当然还有默认的组件 [html] view plaincopy <requestHandler name="standard" class="solr

AFNetworking 3.0 源码解读(四)之 AFURLResponseSerialization

本篇是AFNetworking 3.0 源码解读的第四篇了. AFNetworking 3.0 源码解读(一)之 AFNetworkReachabilityManager AFNetworking 3.0 源码解读(二)之 AFSecurityPolicy AFNetworking 3.0 源码解读(三)之 AFURLRequestSerialization 这次主要讲AFURLResponseSerialization(HTTP响应)这一个类的知识. 这是一个协议,只要遵守这个协议,就要实现N