zoukankan      html  css  js  c++  java
  • 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这个类了。

  • 相关阅读:
    RocketMQ:(2) Broker
    RocketMQ:(1) NameServer、Producer
    数据脱敏:姓名、电话号码等进行字段脱敏,中间部分显示成**
    hibernate中sql查询 字段如何与属性映射
    Java代码编写、代码优化技巧总结
    成长中,感恩遇到的人(1)
    代码中如何优化过多的if..else
    Unsatisfied dependency expressed through field 'rabbitTemplate'错误总结
    解决文件过大,上传失败的问题——大文件分割分片上传
    js 小数运算出现误差的原因
  • 原文地址:https://www.cnblogs.com/panzi/p/5833698.html
Copyright © 2011-2022 走看看