上一章 中,介绍了Options的注册,而在使用时只需要注入 IOption<T> 即可:

public ValuesController(IOptions<MyOptions> options)
{
var opt = options.Value;
}

本章就来详细介绍一下我们最熟悉的IOptions对象。

目录

  1. IOptions
  2. OptionsManager
  3. OptionsFactory
  4. OptionsCache
  5. IOptionsSnapshot

IOptions

IOptions 定义非常简单,只有一个Value属性:

public interface IOptions<out TOptions> where TOptions : class, new()
{
TOptions Value { get; }
}

上一章 中,我们知道它的默认实现为OptionsManager

    services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>)));

OptionsManager

OptionsManager 对options的创建和获取进行管理,我们先看一下它的源码:

public class OptionsManager<TOptions> : IOptions<TOptions>, IOptionsSnapshot<TOptions> where TOptions : class, new()
{
private readonly IOptionsFactory<TOptions> _factory;
private readonly OptionsCache<TOptions> _cache = new OptionsCache<TOptions>(); // Note: this is a private cache public OptionsManager(IOptionsFactory<TOptions> factory)
{
_factory = factory;
} public TOptions Value => Get(Options.DefaultName); public virtual TOptions Get(string name) => _cache.GetOrAdd(name, () => _factory.Create(name ?? Options.DefaultName));
}

如上,OptionsManager 的实现非常简单,使用IOptionsFactory来创建options对象,并使用内部属性OptionsCache<TOptions> _cache进行缓存。

OptionsFactory

IOptionsFactory 只定义了一个Create方法:

public interface IOptionsFactory<TOptions> where TOptions : class, new()
{
TOptions Create(string name);
}

其默认实现为:OptionsFactory

public class OptionsFactory<TOptions> : IOptionsFactory<TOptions> where TOptions : class, new()
{
private readonly IEnumerable<IConfigureOptions<TOptions>> _setups;
private readonly IEnumerable<IPostConfigureOptions<TOptions>> _postConfigures; public OptionsFactory(IEnumerable<IConfigureOptions<TOptions>> setups, IEnumerable<IPostConfigureOptions<TOptions>> postConfigures)
{
_setups = setups;
_postConfigures = postConfigures;
} public TOptions Create(string name)
{
var options = new TOptions();
foreach (var setup in _setups)
{
if (setup is IConfigureNamedOptions<TOptions> namedSetup)
{
namedSetup.Configure(name, options);
}
else if (name == Options.DefaultName)
{
setup.Configure(options);
}
}
foreach (var post in _postConfigures)
{
post.PostConfigure(name, options);
}
return options;
}
}

OptionsFactory的构造函数中注入了IConfigureOptions<>IPostConfigureOptions<>,也就是我们在 上一章 中介绍的 Configure 方法中所注册的配置,而这里使用了 IEnumerable 类型,则表示当注册多个时,为按顺序依次执行。

而我们在第一章中遇到的疑惑也豁然开朗,其Create方法,依次调用完Configure方法后,再调用PostConfigure方法,完成配置项的创建。

OptionsCache

OptionsCache 则是对字典的一个简单封装,就不再多说,直接看代码:

public class OptionsCache<TOptions> : IOptionsMonitorCache<TOptions> where TOptions : class
{
private readonly ConcurrentDictionary<string, Lazy<TOptions>> _cache = new ConcurrentDictionary<string, Lazy<TOptions>>(StringComparer.Ordinal); public void Clear() => _cache.Clear(); public virtual TOptions GetOrAdd(string name, Func<TOptions> createOptions)
{
name = name ?? Options.DefaultName;
return _cache.GetOrAdd(name, new Lazy<TOptions>(createOptions)).Value;
} public virtual bool TryAdd(string name, TOptions options)
{
name = name ?? Options.DefaultName;
return _cache.TryAdd(name, new Lazy<TOptions>(() => options));
} public virtual bool TryRemove(string name)
{
name = name ?? Options.DefaultName;
return _cache.TryRemove(name, out var ignored);
}
}

IOptionsSnapshot

最后再来介绍一下 IOptionsSnapshot :

public interface IOptionsSnapshot<out TOptions> : IOptions<TOptions> where TOptions : class, new()
{
TOptions Get(string name);
}

看到Get方法的Name参数,我想大家便会想到在第一章中所介绍的指定NameConfigure方法,这便是它的用武之地了,通过Name的不同,可以配置同一个Options类型的多个实例。

IOptionsSnapshot的实现与IOptions一样,都是OptionsManager

services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>)));
services.TryAdd(ServiceDescriptor.Scoped(typeof(IOptionsSnapshot<>), typeof(OptionsManager<>)));

通过如上代码,我们也可以发现它与IOptions还有一个本质的区别:IOptionsSnapshot注册的是Scoped类型,每一个请求中,都会创建一个新的OptionsManager对象。这样有什么好处呢?如果我们使用的是Action的方式配置的,那的确是没什么用,但是如果是使用IConfiguration配置的,则在我们修改了配置文件时,重新创建的Options会保持一致。

总结

本文描述了在 .NET Core Options 系统中IOptions的使用及实现原理。由于IOptions使用的是单例模式,因此当配置发生变化时,我们无法获取到最新的配置。而IOptionsSnapshot支持通过name来区分同一类型的不同 options ,并且每次请求都会重新创建 options 实例,相应的,会有稍微的性能损耗。如果我们希望能够监控配置源的变化,来自动更新,则可以使用下一章要介绍的更为强大的 IOptionsMonitor

ASP.NET Core 源码学习之 Options[2]:IOptions的更多相关文章

  1. ASP.NET Core 源码学习之 Options[1]:Configure

    配置的本质就是字符串的键值对,但是对于面向对象语言来说,能使用强类型的配置是何等的爽哉! 目录 ASP.NET Core 配置系统 强类型的 Options Configure 方法 源码解析 ASP ...

  2. ASP.NET Core 源码学习之 Options[4]:IOptionsMonitor

    前面我们讲到 IOptions 和 IOptionsSnapshot,他们两个最大的区别便是前者注册的是单例模式,后者注册的是 Scope 模式.而 IOptionsMonitor 则要求配置源必须是 ...

  3. ASP.NET Core 源码学习之 Options[3]:IOptionsSnapshot

    在 上一章 中,介绍了 IOptions 的使用, 而我们知道,在ConfigurationBuilder的AddJsonFile中,有一个reloadOnChange参数,设置为true时,在配置文 ...

  4. ASP.NET Core源码学习(一)Hosting

    ASP.NET Core源码的学习,我们从Hosting开始, Hosting的GitHub地址为:https://github.com/aspnet/Hosting.git 朋友们可以从以上链接克隆 ...

  5. ASP.NET Core 2.1 源码学习之 Options[2]:IOptions

    在 上一章 中,介绍了Options的注册,而在使用时只需要注入 IOption<T> 即可: public ValuesController(IOptions<MyOptions& ...

  6. ASP.NET Core 2.1 源码学习之 Options[2]:IOptions 【转】

    原文链接:https://www.cnblogs.com/RainingNight/p/strongly-typed-options-ioptions-in-asp-net-core.html 在 上 ...

  7. ASP.NET Core 源码学习之 Logging[2]:Configure

    在上一章中,我们对 ASP.NET Logging 系统做了一个整体的介绍,而在本章中则开始从最基本的配置开始,逐步深入到源码当中去. 默认配置 在 ASP.NET Core 2.0 中,对默认配置做 ...

  8. ASP.NET Core 源码学习之 Logging[1]:Introduction

    在ASP.NET 4.X中,我们通常使用 log4net, NLog 等来记录日志,但是当我们引用的一些第三方类库使用不同的日志框架时,就比较混乱了.而在 ASP.Net Core 中内置了日志系统, ...

  9. ASP.NET Core 源码学习之 Logging[3]:Logger

    上一章,我们介绍了日志的配置,在熟悉了配置之后,自然是要了解一下在应用程序中如何使用,而本章则从最基本的使用开始,逐步去了解去源码. LoggerFactory 我们可以在构造函数中注入 ILogge ...

随机推荐

  1. Firefox实用插件记录

    之前总结过一个软件推荐的小文,用来记录一直以来在软件开发过程中遇到的各种实用的软件.后来发现里面越来越多的记录了Firefox的插件,所以今天决定单独抽出一个页面来记录Firefox的插件.因为平时大 ...

  2. HttpClient--HttpGet使用

    最近公司在做一个爬虫工具,爬取公司现网的数据,留给方通项目使用 用到里阿帕奇的这两个类,在网上看到了一些资料结合自己的应用,这个贴出一个demo import com.alibaba.fastjson ...

  3. redis集群添加删除节点

    Redis3.0集群添加节点 1:首先把需要添加的节点启动 cd /usr/local/cluster/ mkdir 7006 cp /usr/local/cluster/redis.conf  /u ...

  4. Java实现八种排序算法(代码详细解释)

    经过一个多星期的学习.收集.整理,又对数据结构的八大排序算法进行了一个回顾,在测试过程中也遇到了很多问题,解决了很多问题.代码全都是经过小弟运行的,如果有问题,希望能给小弟提出来,共同进步. 参考:数 ...

  5. 关于java和c++中的i++

    看到一个题目,大概是i=i++之类. 乍一看很简单,都知道i++的先参与计算再自增, 所以i不变. 但是仔细一想, 如果i不变, 那么在赋值之后, 自增的i, 增加的是谁呢? 逻辑顺序是怎样的呢? / ...

  6. Linux上rpm方式安装JDK1.7

    说明: 1.Linux版本 CentOS6.5_x86 2.Java版本 JDK1.7 32位的rpm包,所以是以rpm方式安装的java 3.可以使用yum install java从yum源中安装 ...

  7. jQuery选择器的分类之过滤选择器

    jQuery选择器的分类之过滤选择器 上一篇文章为大家简单呢的介绍了jQuery选择器中的基本选择器,层级选择器,表单选择器,接下来就带大家了解一下过滤选择器... 过滤选择器都分为哪些??? 1.基 ...

  8. PHP二位数组按照数组的某个字段值排序

    不多废话 直接代码 /** * @name 排序 按照数组的某个字段值排序 * @param $array 排序数组 $field 排序字段 $direction 排序顺序 * @author wan ...

  9. Apache solr(一)

    概念:Apache Solr 是一个开源的搜索服务器.Solr 使用 Java 语言开发,主要基于 HTTP 和 Apache Lucene 实现.Apache Solr 中存储的资源是以 Docum ...

  10. 微服务框架下的思维变化-OSS.Core基础思路

    如今框架两字已经烂大街了,xx公司架构设计随处可见,不过大多看个热闹,这些框架如何来的,细节又是如何思考的,相互之间的隔离依据又是什么...相信很多朋友应该依然存在自己的疑惑,特别是越来越火热的微服务 ...