_activeHandlers是一个ConcurrentDictionary<>,里面保存的是HttpClient的名称(例如上面代码中的WangPlus)。这里使用Lazy<>是一个使GetOrAdd()方法保持线程安全的技巧。实际创建处理管道的工作在CreateHandlerEntry中,它创建了一个ActiveHandlerTrackingEntry。
ActiveHandlerTrackingEntry是一个不可变的对象,包含HttpMessageHandler和IServiceScope注入。此外,它还包含一个与StartExpiryTimer()一起使用的内部计时器,用于在计时器过期时调用回调函数。
看一下ActiveHandlerTrackingEntry的定义:
internal class ActiveHandlerTrackingEntry{
public LifetimeTrackingHttpMessageHandler Handler { get; private set; }
public TimeSpan Lifetime { get; }
public string Name { get; }
public IServiceScope Scope { get; }
public void StartExpiryTimer(TimerCallback callback)
{
// Starts the internal timer
// Executes the callback after Lifetime has expired.
// If the timer has already started, is noop
}
}
因此CreateHandler方法要么创建一个新的ActiveHandlerTrackingEntry,要么从字典中检索条目,然后启动计时器。
下一节,我们来看看CreateHandlerEntry()方法如何创建ActiveHandlerTrackingEntry实例。
三、在CreateHandlerEntry中创建和跟踪HttpMessageHandlerCreateHandlerEntry方法是创建HttpClient处理管道的地方。
这个部分代码有点复杂,我们简化一下,以研究过程为主:
private readonly IServiceProvider _services;private readonly IHttpMessageHandlerBuilderFilter[] _filters;
private ActiveHandlerTrackingEntry CreateHandlerEntry(string name)
{
IServiceScope scope = _services.CreateScope();
IServiceProvider services = scope.ServiceProvider;
HttpClientFactoryOptions options = _optionsMonitor.Get(name);
HttpMessageHandlerBuilder builder = services.GetRequiredService<HttpMessageHandlerBuilder>();
builder.Name = name;
Action<HttpMessageHandlerBuilder> configure = Configure;
for (int i = _filters.Length - 1; i >= 0; i--)
{
configure = _filters[i].Configure(configure);
}
configure(builder);
var handler = new LifetimeTrackingHttpMessageHandler(builder.Build());
return new ActiveHandlerTrackingEntry(name, handler, scope, options.HandlerLifetime);
void Configure(HttpMessageHandlerBuilder b)
{
for (int i = 0; i < options.HttpMessageHandlerBuilderActions.Count; i++)
{
options.HttpMessageHandlerBuilderActions[i](b);
}
}
}
先用根DI容器创建一个IServiceScope,从关联的IServiceProvider中获取关联的服务,再从HttpClientFactoryOptions中找到对应名称的HttpClient和它的配置。
从容器中查找的下一项是HttpMessageHandlerBuilder,默认值是DefaultHttpMessageHandlerBuilder,这个值通过创建一个主处理程序(负责建立Socket套接字和发送请求的HttpClientHandler)来构建处理管道。我们可以通过添加附加的委托来包装这个主处理程序,来为请求和响应创建自定义管理。
附加的委托DelegatingHandlers类似于Core的中间件管道:
Configure()根据Startup.ConfigureServices()提供的配置构建DelegatingHandlers管道;
IHttpMessageHandlerBuilderFilter是注入到IHttpClientFactory构造函数中的过滤器,用于在委托处理管道中添加额外的处理程序。
IHttpMessageHandlerBuilderFilter类似于IStartupFilters,默认注册的是LoggingHttpMessageHandlerBuilderFilter。这个过滤器向委托管道添加了两个额外的处理程序:
管道开始位置的LoggingScopeHttpMessageHandler,会启动一个新的日志Scope;
管道末端的LoggingHttpMessageHandler,在请求被发送到主HttpClientHandler之前,记录有关请求和响应的日志;