NetCore启动流程源码分析

netcore优势

  1. 优秀开发模式
  2. 性能/稳定
  3. IOC容器本身就是个对象
  4. 注册类型/功能解析/某个类所依赖的类的对象

程序启动流程

  1. 创建主机与主机配置
  2. 依赖注入、服务、管道、中间件、应用配置、多环境、日志、路由、异常处理、静态文件、部署

主机是什么?

Host:主机实际就一个封装了应用资源对象

主机的作用是什么?

主机负责应用程序的启动、生命周期的管理、配置服务和请求处理管道等

详细启动流程

可以看出WebApi的启动,其实就是控制台程序启动

1. Host.CreateDefaultBuilder方法

public static IHostBuilder CreateDefaultBuilder(string[] args)
        {
         // 实例化一个HostBuilder
            var builder = new HostBuilder();
         // 设置根目录
            builder.UseContentRoot(Directory.GetCurrentDirectory());
         // 设置 Host相关配置的配置源
            builder.ConfigureHostConfiguration(config =>
            {
          // 从环境变量中获取,前缀名为DOTNET_
                config.AddEnvironmentVariables(prefix: "DOTNET_");
                // 如果命令行中有参数,可从命令行中读取
                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            });
     
         // 设置应用程序配置的配置源
            builder.ConfigureAppConfiguration((hostingContext, config) =>
            {
                var env = hostingContext.HostingEnvironment;
          //根据运行环境加载不同的配置文件,并开启了热更新
                config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                      .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

                if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName))
                {
                    var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
                    if (appAssembly != null)
                    {
                        config.AddUserSecrets(appAssembly, optional: true);
                    }
                }
          //可从环境变量中获取
                config.AddEnvironmentVariables();
               // 如果命令行中有参数,可从命令行中读取
                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            })
         // 配置日志显示
            .ConfigureLogging((hostingContext, logging) =>
            {
          //判断操作系统
                var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
          // 如果是Windows系统,配置对应的显示级别
                // IMPORTANT: This needs to be added *before* configuration is loaded, this lets
                // the defaults be overridden by the configuration.
                if (isWindows)
                {
                    // Default the EventLogLoggerProvider to warning or above
                    logging.AddFilter<EventLogLoggerProvider>(level => level >= LogLevel.Warning);
                }
           //获取配置文件中Logging 段相关的配置信息添加到日志配置中
                logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                // 在控制台输出,所以启动程序的时候就看见输出日志
           logging.AddConsole();
          // 在Debug窗口输出
                logging.AddDebug();
                logging.AddEventSourceLogger();

          // 如果是Windows系统,可以在系统日志中输出日志
                if (isWindows)
                {
                    // Add the EventLogLoggerProvider on windows machines
                    logging.AddEventLog();
                }
            })//使用默认的依赖注入容器
            .UseDefaultServiceProvider((context, options) =>
            {
                var isDevelopment = context.HostingEnvironment.IsDevelopment();
                options.ValidateScopes = isDevelopment;
                options.ValidateOnBuild = isDevelopment;
            });

            return builder;
        }

 2. ConfigureWebHostDefaults 方法

public static IHostBuilder ConfigureWebHostDefaults(this IHostBuilder builder, Action<IWebHostBuilder> configure)
        {
            return builder.ConfigureWebHost(webHostBuilder =>
            {
          //指定是用的服务器及集成一些默认管道
                WebHost.ConfigureWebDefaults(webHostBuilder);
          // 调用传入的委托,这里是外部指定Startup类做服务注册和管道配置
                configure(webHostBuilder);
            });
        }

2.1  WebHost.ConfigureWebDefaults方法

internal static void ConfigureWebDefaults(IWebHostBuilder builder)
        {
            builder.ConfigureAppConfiguration((ctx, cb) =>
            {
                if (ctx.HostingEnvironment.IsDevelopment())
                {
            //静态文件环境的配置启用
                    StaticWebAssetsLoader.UseStaticWebAssets(ctx.HostingEnvironment, ctx.Configuration);
                }
            });
            // 指定Kestrel作为默认的Web服务器
            builder.UseKestrel((builderContext, options) =>
            {
                options.Configure(builderContext.Configuration.GetSection("Kestrel"));
            })// 服务中间的注册,包含路的中间件注册
            .ConfigureServices((hostingContext, services) =>
            {
          // 针对配置节点AllowedHosts改变时的回调
                // Fallback
                services.PostConfigure<HostFilteringOptions>(options =>
                {
                    if (options.AllowedHosts == null || options.AllowedHosts.Count == 0)
                    {
                        // "AllowedHosts": "localhost;127.0.0.1;[::1]"
                        var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                        // Fall back to "*" to disable.
                        options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" });
                    }
                });
          //对应配置改变时触发通知
                // Change notification
                services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>(
                            new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration));

                services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();

                if (string.Equals("true", hostingContext.Configuration["ForwardedHeaders_Enabled"], StringComparison.OrdinalIgnoreCase))
                {
                    services.Configure<ForwardedHeadersOptions>(options =>
                    {
                        options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
                        // Only loopback proxies are allowed by default. Clear that restriction because forwarders are
                        // being enabled by explicit configuration.
                        options.KnownNetworks.Clear();
                        options.KnownProxies.Clear();
                    });

                    services.AddTransient<IStartupFilter, ForwardedHeadersStartupFilter>();
                }
                services.AddRouting();
            })//对使用IIS相关中间件
            .UseIIS()
            .UseIISIntegration();
        }

3. Build方法,其实这个方法就是根据之前配置构造出一个IHost对象

public IHost Build()
        {
            if (_hostBuilt)
            {
                throw new InvalidOperationException("Build can only be called once.");
            }
            _hostBuilt = true;
         // 执行ConfigureHostConfiguration添加的一系列配置回调方法
            BuildHostConfiguration();
         // 运行环境相关创建,如ApplicationName、EnvironmentName、ContentRootPath等
            CreateHostingEnvironment();
         // 构建HostBuilder
            CreateHostBuilderContext();
            // 执行ConfigureAppConfigureation添加的一系列配置回调方法
            BuildAppConfiguration();
         // 注入默认服务如:IHost、ILogging等,执行ConfigureServices添加的一系列回调方法
            CreateServiceProvider();
            return _appServices.GetRequiredService<IHost>();
        }

4. Run()方法,开启服务器,之后就可以进行请求

借鉴出处

https://www.cnblogs.com/zoe-zyq/p/13362196.html

https://www.sohu.com/a/428320898_468635

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xman_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值