void InstanceImpl::initialize(const Options& options,
                              Network::Address::InstanceConstSharedPtr local_address,
                              ComponentFactory& component_factory, ListenerHooks& hooks) {
  ENVOY_LOG(info, "initializing epoch {} (base id={}, hot restart version={})",
            options.restartEpoch(), restarter_.baseId(), restarter_.version());

  ENVOY_LOG(info, "statically linked extensions:");
  for (const auto& ext : Envoy::Registry::FactoryCategoryRegistry::registeredFactories()) {
    ENVOY_LOG(info, "  {}: {}", ext.first, absl::StrJoin(ext.second->registeredNames(), ", "));
  }

  // Handle configuration that needs to take place prior to the main configuration load.
  InstanceUtil::loadBootstrapConfig(bootstrap_, options,
                                    messageValidationContext().staticValidationVisitor(), *api_);
  bootstrap_config_update_time_ = time_source_.systemTime();

  // Immediate after the bootstrap has been loaded, override the header prefix, if configured to
  // do so. This must be set before any other code block references the HeaderValues ConstSingleton.
  if (!bootstrap_.header_prefix().empty()) {
    // setPrefix has a release assert verifying that setPrefix() is not called after prefix()
    ThreadSafeSingleton<Http::PrefixValue>::get().setPrefix(bootstrap_.header_prefix().c_str());
  }
  // TODO(mattklein123): Custom O(1) headers can be registered at this point for creating/finalizing
  // any header maps.
  ENVOY_LOG(info, "HTTP header map info:");
  for (const auto& info : Http::HeaderMapImplUtility::getAllHeaderMapImplInfo()) {
    ENVOY_LOG(info, "  {}: {} bytes: {}", info.name_, info.size_,
              absl::StrJoin(info.registered_headers_, ","));
  }

  // Needs to happen as early as possible in the instantiation to preempt the objects that require
  // stats.
  stats_store_.setTagProducer(Config::Utility::createTagProducer(bootstrap_));
  stats_store_.setStatsMatcher(Config::Utility::createStatsMatcher(bootstrap_));

  const std::string server_stats_prefix = "server.";
  server_stats_ = std::make_unique<ServerStats>(
      ServerStats{ALL_SERVER_STATS(POOL_COUNTER_PREFIX(stats_store_, server_stats_prefix),
                                   POOL_GAUGE_PREFIX(stats_store_, server_stats_prefix),
                                   POOL_HISTOGRAM_PREFIX(stats_store_, server_stats_prefix))});
  validation_context_.static_warning_validation_visitor().setUnknownCounter(
      server_stats_->static_unknown_fields_);
  validation_context_.dynamic_warning_validation_visitor().setUnknownCounter(
      server_stats_->dynamic_unknown_fields_);

  initialization_timer_ = std::make_unique<Stats::HistogramCompletableTimespanImpl>(
      server_stats_->initialization_time_ms_, timeSource());
  server_stats_->concurrency_.set(options_.concurrency());
  server_stats_->hot_restart_epoch_.set(options_.restartEpoch());

  assert_action_registration_ = Assert::setDebugAssertionFailureRecordAction(
      [this]() { server_stats_->debug_assertion_failures_.inc(); });
  envoy_bug_action_registration_ = Assert::setEnvoyBugFailureRecordAction(
      [this]() { server_stats_->envoy_bug_failures_.inc(); });

  InstanceImpl::failHealthcheck(false);

  // Check if bootstrap has server version override set, if yes, we should use that as
  // 'server.version' stat.
  uint64_t version_int;
  if (bootstrap_.stats_server_version_override().value() > 0) {
    version_int = bootstrap_.stats_server_version_override().value();
  } else {
    if (!StringUtil::atoull(VersionInfo::revision().substr(0, 6).c_str(), version_int, 16)) {
      throw EnvoyException("compiled GIT SHA is invalid. Invalid build.");
    }
  }
  server_stats_->version_.set(version_int);

  bootstrap_.mutable_node()->set_hidden_envoy_deprecated_build_version(VersionInfo::version());
  bootstrap_.mutable_node()->set_user_agent_name("envoy");
  *bootstrap_.mutable_node()->mutable_user_agent_build_version() = VersionInfo::buildVersion();
  for (const auto& ext : Envoy::Registry::FactoryCategoryRegistry::registeredFactories()) {
    for (const auto& name : ext.second->allRegisteredNames()) {
      auto* extension = bootstrap_.mutable_node()->add_extensions();
      extension->set_name(std::string(name));
      extension->set_category(ext.first);
      auto const version = ext.second->getFactoryVersion(name);
      if (version) {
        *extension->mutable_version() = version.value();
      }
      extension->set_disabled(ext.second->isFactoryDisabled(name));
    }
  }

  local_info_ = std::make_unique<LocalInfo::LocalInfoImpl>(
      bootstrap_.node(), local_address, options.serviceZone(), options.serviceClusterName(),
      options.serviceNodeName());

  Configuration::InitialImpl initial_config(bootstrap_);

  // Learn original_start_time_ if our parent is still around to inform us of it.
  restarter_.sendParentAdminShutdownRequest(original_start_time_);
  admin_ = std::make_unique<AdminImpl>(initial_config.admin().profilePath(), *this);
  if (initial_config.admin().address()) {
    if (initial_config.admin().accessLogPath().empty()) {
      throw EnvoyException("An admin access log path is required for a listening server.");
    }
    ENVOY_LOG(info, "admin address: {}", initial_config.admin().address()->asString());
    admin_->startHttpListener(initial_config.admin().accessLogPath(), options.adminAddressPath(),
                              initial_config.admin().address(),
                              initial_config.admin().socketOptions(),
                              stats_store_.createScope("listener.admin."));
  } else {
    ENVOY_LOG(warn, "No admin address given, so no admin HTTP server started.");
  }
  config_tracker_entry_ =
      admin_->getConfigTracker().add("bootstrap", [this] { return dumpBootstrapConfig(); });
  if (initial_config.admin().address()) {
    admin_->addListenerToHandler(handler_.get());
  }

  loadServerFlags(initial_config.flagsPath());

  secret_manager_ = std::make_unique<Secret::SecretManagerImpl>(admin_->getConfigTracker());

  // Initialize the overload manager early so other modules can register for actions.
  overload_manager_ = std::make_unique<OverloadManagerImpl>(
      *dispatcher_, stats_store_, thread_local_, bootstrap_.overload_manager(),
      messageValidationContext().staticValidationVisitor(), *api_);

  heap_shrinker_ =
      std::make_unique<Memory::HeapShrinker>(*dispatcher_, *overload_manager_, stats_store_);

  // Workers get created first so they register for thread local updates.
  listener_manager_ = std::make_unique<ListenerManagerImpl>(
      *this, listener_component_factory_, worker_factory_, bootstrap_.enable_dispatcher_stats());

  // The main thread is also registered for thread local updates so that code that does not care
  // whether it runs on the main thread or on workers can still use TLS.
  thread_local_.registerThread(*dispatcher_, true);

  // We can now initialize stats for threading.
  stats_store_.initializeThreading(*dispatcher_, thread_local_);

  // It's now safe to start writing stats from the main thread's dispatcher.
  if (bootstrap_.enable_dispatcher_stats()) {
    dispatcher_->initializeStats(stats_store_, "server.");
  }

  // The broad order of initialization from this point on is the following:
  // 1. Statically provisioned configuration (bootstrap) are loaded.
  // 2. Cluster manager is created and all primary clusters (i.e. with endpoint assignments
  //    provisioned statically in bootstrap, discovered through DNS or file based CDS) are
  //    initialized.
  // 3. Various services are initialized and configured using the bootstrap config.
  // 4. RTDS is initialized using primary clusters. This  allows runtime overrides to be fully
  //    configured before the rest of xDS configuration is provisioned.
  // 5. Secondary clusters (with endpoint assignments provisioned by xDS servers) are initialized.
  // 6. The rest of the dynamic configuration is provisioned.
  //
  // Please note: this order requires that RTDS is provisioned using a primary cluster. If RTDS is
  // provisioned through ADS then ADS must use primary cluster as well. This invariant is enforced
  // during RTDS initialization and invalid configuration will be rejected.

  // Runtime gets initialized before the main configuration since during main configuration
  // load things may grab a reference to the loader for later use.
  runtime_singleton_ = std::make_unique<Runtime::ScopedLoaderSingleton>(
      component_factory.createRuntime(*this, initial_config));
  hooks.onRuntimeCreated();

  // Once we have runtime we can initialize the SSL context manager.
  ssl_context_manager_ = createContextManager("ssl_context_manager", time_source_);

  const bool use_tcp_for_dns_lookups = bootstrap_.use_tcp_for_dns_lookups();
  dns_resolver_ = dispatcher_->createDnsResolver({}, use_tcp_for_dns_lookups);

  cluster_manager_factory_ = std::make_unique<Upstream::ProdClusterManagerFactory>(
      *admin_, Runtime::LoaderSingleton::get(), stats_store_, thread_local_, *random_generator_,
      dns_resolver_, *ssl_context_manager_, *dispatcher_, *local_info_, *secret_manager_,
      messageValidationContext(), *api_, http_context_, grpc_context_, access_log_manager_,
      *singleton_manager_);

  // Now the configuration gets parsed. The configuration may start setting
  // thread local data per above. See MainImpl::initialize() for why ConfigImpl
  // is constructed as part of the InstanceImpl and then populated once
  // cluster_manager_factory_ is available.
  config_.initialize(bootstrap_, *this, *cluster_manager_factory_);

  // Instruct the listener manager to create the LDS provider if needed. This must be done later
  // because various items do not yet exist when the listener manager is created.
  if (bootstrap_.dynamic_resources().has_lds_config()) {
    listener_manager_->createLdsApi(bootstrap_.dynamic_resources().lds_config());
  }

  // We have to defer RTDS initialization until after the cluster manager is
  // instantiated (which in turn relies on runtime...).
  Runtime::LoaderSingleton::get().initialize(clusterManager());

  clusterManager().setPrimaryClustersInitializedCb(
      [this]() { onClusterManagerPrimaryInitializationComplete(); });

  for (Stats::SinkPtr& sink : config_.statsSinks()) {
    stats_store_.addSink(*sink);
  }

  // Some of the stat sinks may need dispatcher support so don't flush until the main loop starts.
  // Just setup the timer.
  stat_flush_timer_ = dispatcher_->createTimer([this]() -> void { flushStats(); });
  stat_flush_timer_->enableTimer(config_.statsFlushInterval());

  // GuardDog (deadlock detection) object and thread setup before workers are
  // started and before our own run() loop runs.
  guard_dog_ = std::make_unique<Server::GuardDogImpl>(stats_store_, config_, *api_);

  for (const auto& bootstrap_extension : bootstrap_.bootstrap_extensions()) {
    auto& factory = Config::Utility::getAndCheckFactory<Configuration::BootstrapExtensionFactory>(
        bootstrap_extension);
    auto config = Config::Utility::translateAnyToFactoryConfig(
        bootstrap_extension.typed_config(), messageValidationContext().staticValidationVisitor(),
        factory);
    bootstrap_extensions_.push_back(
        factory.createBootstrapExtension(*config, serverFactoryContext()));
  }
}