DefaultServerConfig buildServerConfig(List<ServerPort> serverPorts) {
        final AnnotatedServiceExtensions extensions =
                virtualHostTemplate.annotatedServiceExtensions();
        assert extensions != null;
        final DependencyInjector dependencyInjector = dependencyInjectorOrReflective();

        final UnloggedExceptionsReporter unloggedExceptionsReporter;
        if (unloggedExceptionsReportIntervalMillis > 0) {
            unloggedExceptionsReporter = UnloggedExceptionsReporter.of(
                    meterRegistry, unloggedExceptionsReportIntervalMillis);
            serverListeners.add(unloggedExceptionsReporter);
        } else {
            unloggedExceptionsReporter = null;
        }

        final ServerErrorHandler errorHandler =
                new CorsServerErrorHandler(
                        this.errorHandler == null ? ServerErrorHandler.ofDefault()
                                                  : this.errorHandler.orElse(ServerErrorHandler.ofDefault()));
        final VirtualHost defaultVirtualHost =
                defaultVirtualHostBuilder.build(virtualHostTemplate, dependencyInjector,
                                                unloggedExceptionsReporter, errorHandler, tlsProvider);
        final List<VirtualHost> virtualHosts =
                virtualHostBuilders.stream()
                                   .map(vhb -> vhb.build(virtualHostTemplate, dependencyInjector,
                                                         unloggedExceptionsReporter, errorHandler, tlsProvider))
                                   .collect(toImmutableList());
        // Pre-populate the domain name mapping for later matching.
        final Mapping<String, SslContext> sslContexts;
        final SslContext defaultSslContext = findDefaultSslContext(defaultVirtualHost, virtualHosts);
        final Collection<ServerPort> ports;

        for (ServerPort port : this.ports) {
            checkState(port.protocols().stream().anyMatch(p -> p != PROXY),
                       "protocols: %s (expected: at least one %s or %s)",
                       port.protocols(), HTTP, HTTPS);
        }

        // The port numbers of port-based virtual hosts must exist in 'ServerPort's.
        final List<VirtualHost> portBasedVirtualHosts = virtualHosts.stream()
                                                                    .filter(v -> v.port() > 0)
                                                                    .collect(toImmutableList());
        final List<Integer> portNumbers = this.ports.stream()
                                                    .map(port -> port.localAddress().getPort())
                                                    .filter(port -> port > 0)
                                                    .collect(toImmutableList());
        for (VirtualHost virtualHost : portBasedVirtualHosts) {
            final int virtualHostPort = virtualHost.port();
            final boolean portMatched = portNumbers.stream().anyMatch(port -> port == virtualHostPort);
            checkState(portMatched, "virtual host port: %s (expected: one of %s)",
                       virtualHostPort, portNumbers);
        }

        checkState(defaultSslContext == null || tlsProvider == null,
                   "Can't set %s with a static TLS setting", TlsProvider.class.getSimpleName());
        if (defaultSslContext == null && tlsProvider == null) {
            sslContexts = null;
            if (!serverPorts.isEmpty()) {
                ports = resolveDistinctPorts(serverPorts);
                for (final ServerPort p : ports) {
                    if (p.hasTls()) {
                        throw new IllegalArgumentException("TLS not configured; cannot serve HTTPS");
                    }
                }
            } else {
                ports = ImmutableList.of(new ServerPort(0, HTTP));
            }
        } else {
            if (Flags.tlsEngineType() != TlsEngineType.OPENSSL && !SystemInfo.jettyAlpnOptionalOrAvailable()) {
                throw new IllegalStateException(
                        "TLS configured but this is Java 8 and neither OpenSSL nor Jetty ALPN could be " +
                        "detected. To use TLS with Armeria, you must either use Java 9+, enable OpenSSL, " +
                        "usually by adding a build dependency on the " +
                        "io.netty:netty-tcnative-boringssl-static artifact or enable Jetty ALPN as described " +
                        "at https://www.eclipse.org/jetty/documentation/9.4.x/alpn-chapter.html");
            }

            if (!serverPorts.isEmpty()) {
                ports = resolveDistinctPorts(serverPorts);
            } else {
                ports = ImmutableList.of(new ServerPort(0, HTTPS));
            }

            if (defaultSslContext != null) {
                final DomainMappingBuilder<SslContext>
                        mappingBuilder = new DomainMappingBuilder<>(defaultSslContext);
                for (VirtualHost h : virtualHosts) {
                    final SslContext sslCtx = h.sslContext();
                    if (sslCtx != null) {
                        final String originalHostnamePattern = h.originalHostnamePattern();
                        // The SslContext for the default virtual host was added when creating
                        // DomainMappingBuilder.
                        if (!"*".equals(originalHostnamePattern)) {
                            mappingBuilder.add(originalHostnamePattern, sslCtx);
                        }
                    }
                }
                sslContexts = mappingBuilder.build();
            } else {
                final TlsEngineType tlsEngineType = defaultVirtualHost.tlsEngineType();
                assert tlsEngineType != null;
                assert tlsProvider != null;
                sslContexts = new TlsProviderMapping(tlsProvider, tlsEngineType, tlsConfig, meterRegistry);
            }
        }
        if (pingIntervalMillis > 0) {
            pingIntervalMillis = Math.max(pingIntervalMillis, MIN_PING_INTERVAL_MILLIS);
            if (idleTimeoutMillis > 0 && pingIntervalMillis >= idleTimeoutMillis) {
                pingIntervalMillis = 0;
            }
        }

        if (maxConnectionAgeMillis > 0) {
            maxConnectionAgeMillis = Math.max(maxConnectionAgeMillis, MIN_MAX_CONNECTION_AGE_MILLIS);
            if (idleTimeoutMillis == 0 || idleTimeoutMillis > maxConnectionAgeMillis) {
                idleTimeoutMillis = maxConnectionAgeMillis;
            }
        }

        final Map<ChannelOption<?>, Object> newChildChannelOptions =
                ChannelUtil.applyDefaultChannelOptions(
                        childChannelOptions, idleTimeoutMillis, pingIntervalMillis);
        final BlockingTaskExecutor blockingTaskExecutor = defaultVirtualHost.blockingTaskExecutor();

        return new DefaultServerConfig(
                ports, setSslContextIfAbsent(defaultVirtualHost, defaultSslContext),
                virtualHosts, workerGroup, shutdownWorkerGroupOnStop, startStopExecutor, maxNumConnections,
                idleTimeoutMillis, keepAliveOnPing, pingIntervalMillis, maxConnectionAgeMillis,
                maxNumRequestsPerConnection,
                connectionDrainDurationMicros, http2InitialConnectionWindowSize,
                http2InitialStreamWindowSize, http2MaxStreamsPerConnection,
                http2MaxFrameSize, http2MaxHeaderListSize,
                http2MaxResetFramesPerWindow, http2MaxResetFramesWindowSeconds,
                http1MaxInitialLineLength, http1MaxHeaderSize,
                http1MaxChunkSize, gracefulShutdown,
                blockingTaskExecutor,
                meterRegistry, proxyProtocolMaxTlvSize, channelOptions, newChildChannelOptions,
                childChannelPipelineCustomizer,
                clientAddressSources, clientAddressTrustedProxyFilter, clientAddressFilter, clientAddressMapper,
                enableServerHeader, enableDateHeader, errorHandler, sslContexts,
                http1HeaderNaming, dependencyInjector, absoluteUriTransformer,
                unloggedExceptionsReportIntervalMillis, ImmutableList.copyOf(shutdownSupports));
    }
Returns a newly-created {@link Server} based on the configuration properties set so far.
core/src/main/java/com/linecorp/armeria/server/ServerBuilder.java