继续使用老配方,我们查看StartupLoader的FindConfigureContainerDelegate方法实现
[点击查看源码👈]
internal static ConfigureContainerBuilder FindConfigureContainerDelegate(Type startupType, string environmentName) { //根据startupType和根据environmentName构建的Configure{0}Services字符串先去查找返回类型为IServiceProvider的方法 var configureMethod = FindMethod(startupType, "Configure{0}Container", environmentName, typeof(void), required: false); //用查找到的方法去初始化ConfigureContainerBuilder return new ConfigureContainerBuilder(configureMethod); }
果然还是这个配方这个味道,废话不多说直接查看ConfigureContainerBuilder源码
[点击查看源码👈]
internal class ConfigureContainerBuilder { public ConfigureContainerBuilder(MethodInfo configureContainerMethod) { MethodInfo = configureContainerMethod; } public MethodInfo MethodInfo { get; } public Func<Action<object>, Action<object>> ConfigureContainerFilters { get; set; } = f => f; public Action<object> Build(object instance) => container => Invoke(instance, container); //查找容器类型,其实就是ConfigureContainer方法的的唯一参数 public Type GetContainerType() { var parameters = MethodInfo.GetParameters(); //ConfigureContainer方法只能包含一个参数 if (parameters.Length != 1) { throw new InvalidOperationException($"The {MethodInfo.Name} method must take only one parameter."); } return parameters[0].ParameterType; } private void Invoke(object instance, object container) { ConfigureContainerFilters(StartupConfigureContainer)(container); void StartupConfigureContainer(object containerBuilder) => InvokeCore(instance, containerBuilder); } //根据传递的container对象执行ConfigureContainer方法逻辑比如使用autofac时ConfigureContainer(ContainerBuilder) private void InvokeCore(object instance, object container) { if (MethodInfo == null) { return; } var arguments = new object[1] { container }; MethodInfo.InvokeWithoutWrappingExceptions(instance, arguments); } }
果不其然千年老方下来还是那个味道,和ConfigureServices、Configure方法思路几乎一致。这里需要注意的是GetContainerType获取的容器类型是ConfigureContainer方法的唯一参数即容器类型,如果传递多个参数则直接抛出异常。其实Startup的ConfigureContainer方法经过花里胡哨的一番操作之后,最终还是转换成了雷士如下的操作方式,这个我们在上面代码中构建actionType的时候就可以看出,最终通过查找到的容器类型去完成注册等相关操作,这里就不过多的讲解了
Host.CreateDefaultBuilder(args) .ConfigureContainer<ContainerBuilder>((context,container)=> { container.RegisterType<PersonService>().As<IPersonService>().InstancePerLifetimeScope(); });
总结
本篇文章我们主要是围绕着Startup是如何被初始化进行讲解的,分别讲解了Startup是如何被实例化的,为何Startup的构造函数只能传递IWebHostEnvironment、IHostEnvironment、IConfiguration类型的参数,以及ConfigureServices、Configure、ConfigureContainer方法是如何查找到并被初始化调用的。其中虽然涉及到的代码比较多,但是整体思路在阅读源码后还是比较清晰的。由于笔者文笔有限,可能许多地方描述的不够清晰,亦或是本人能力有限理解的不够透彻,不过本人在文章中都标记了源码所在位置的链接,如果有感兴趣的同学可以自行点击连接查看源码。Startup类比较常用,如果能够更深层次的了解其原理,对我们实际编程过程中会有很大的帮助,同时呼吁更多的小伙伴们深入阅读了解.NET Core的源码并分享出来。如有各位有疑问或者有了解的更透彻的,欢迎评论区提问或批评指导。
您可能感兴趣的文章: