VirtualHost build(VirtualHostBuilder template, DependencyInjector dependencyInjector,
                      @Nullable UnloggedExceptionsReporter unloggedExceptionsReporter,
                      ServerErrorHandler serverErrorHandler, @Nullable TlsProvider tlsProvider) {
        requireNonNull(template, "template");

        if (defaultHostname == null) {
            if (hostnamePattern != null) {
                defaultHostname = hostnamePattern.startsWith("*.") ? hostnamePattern.substring(2)
                                                                   : hostnamePattern;
            } else {
                defaultHostname = SystemInfo.hostname();
            }
        }

        if (hostnamePattern == null) {
            hostnamePattern = defaultVirtualHost ? "*" : "*." + defaultHostname;
        }

        ensureHostnamePatternMatchesDefaultHostname(hostnamePattern, defaultHostname);

        // Retrieve all settings as a local copy. Use default builder's properties if not set.
        assert template.defaultServiceNaming != null;
        final ServiceNaming defaultServiceNaming =
                this.defaultServiceNaming != null ?
                this.defaultServiceNaming : template.defaultServiceNaming;

        final String defaultLogName =
                this.defaultLogName != null ?
                this.defaultLogName : template.defaultLogName;

        assert template.requestTimeoutMillis != null;
        final long requestTimeoutMillis =
                this.requestTimeoutMillis != null ?
                this.requestTimeoutMillis : template.requestTimeoutMillis;

        assert template.maxRequestLength != null;
        final long maxRequestLength =
                this.maxRequestLength != null ?
                this.maxRequestLength : template.maxRequestLength;

        assert template.verboseResponses != null;
        final boolean verboseResponses =
                this.verboseResponses != null ?
                this.verboseResponses : template.verboseResponses;

        assert template.requestAutoAbortDelayMillis != null;
        final long requestAutoAbortDelayMillis =
                this.requestAutoAbortDelayMillis != null ?
                this.requestAutoAbortDelayMillis : template.requestAutoAbortDelayMillis;

        assert template.rejectedRouteHandler != null;
        final RejectedRouteHandler rejectedRouteHandler =
                this.rejectedRouteHandler != null ?
                this.rejectedRouteHandler : template.rejectedRouteHandler;

        final AccessLogWriter accessLogWriter;
        if (this.accessLogWriter != null) {
            accessLogWriter = this.accessLogWriter;
        } else {
            accessLogWriter = template.accessLogWriter != null ?
                              template.accessLogWriter : AccessLogWriter.disabled();
        }

        final Function<? super VirtualHost, ? extends Logger> accessLoggerMapper =
                this.accessLoggerMapper != null ?
                this.accessLoggerMapper : template.accessLoggerMapper;

        final AnnotatedServiceExtensions extensions =
                annotatedServiceExtensions != null ?
                annotatedServiceExtensions : template.annotatedServiceExtensions;

        final BlockingTaskExecutor blockingTaskExecutor;
        if (this.blockingTaskExecutor != null) {
            blockingTaskExecutor = this.blockingTaskExecutor;
        } else {
            blockingTaskExecutor = template.blockingTaskExecutor;
        }

        final SuccessFunction successFunction;
        if (this.successFunction != null) {
            successFunction = this.successFunction;
        } else {
            successFunction = template.successFunction;
        }
        final Path multipartUploadsLocation =
                this.multipartUploadsLocation != null ?
                this.multipartUploadsLocation : template.multipartUploadsLocation;
        final MultipartRemovalStrategy multipartRemovalStrategy =
                this.multipartRemovalStrategy != null ?
                this.multipartRemovalStrategy : template.multipartRemovalStrategy;

        final HttpHeaders defaultHeaders =
                mergeDefaultHeaders(template.defaultHeaders, this.defaultHeaders.build());

        final Function<? super RoutingContext, ? extends RequestId> requestIdGenerator =
                this.requestIdGenerator != null ?
                this.requestIdGenerator : template.requestIdGenerator;
        final ServiceErrorHandler serviceErrorHandler = serverErrorHandler.asServiceErrorHandler();
        final ServiceErrorHandler defaultErrorHandler =
                errorHandler != null ? errorHandler.orElse(serviceErrorHandler) : serviceErrorHandler;

        final Supplier<AutoCloseable> contextHook = mergeHooks(template.contextHook, this.contextHook);

        final EventLoopGroup serviceWorkerGroup;
        if (this.serviceWorkerGroup != null) {
            serviceWorkerGroup = this.serviceWorkerGroup;
        } else if (template.serviceWorkerGroup != null) {
            serviceWorkerGroup = template.serviceWorkerGroup;
        } else {
            serviceWorkerGroup = serverBuilder.workerGroup;
        }

        assert defaultServiceNaming != null;
        assert rejectedRouteHandler != null;
        assert accessLoggerMapper != null;
        assert extensions != null;
        assert blockingTaskExecutor != null;
        assert successFunction != null;
        assert multipartUploadsLocation != null;
        assert multipartRemovalStrategy != null;
        assert requestIdGenerator != null;

        final List<ServiceConfig> serviceConfigs = getServiceConfigSetters(template)
                .stream()
                .flatMap(cfgSetters -> {
                    if (cfgSetters instanceof AbstractAnnotatedServiceConfigSetters) {
                        return ((AbstractAnnotatedServiceConfigSetters<?>) cfgSetters)
                                .buildServiceConfigBuilder(extensions, dependencyInjector).stream();
                    } else if (cfgSetters instanceof ServiceConfigBuilder) {
                        return Stream.of((ServiceConfigBuilder) cfgSetters);
                    } else {
                        // Should not reach here.
                        throw new Error("Unexpected service config setters type: " +
                                        cfgSetters.getClass().getSimpleName());
                    }
                }).map(cfgBuilder -> {
                    return cfgBuilder.build(defaultServiceNaming, defaultLogName, requestTimeoutMillis,
                                            maxRequestLength, verboseResponses, accessLogWriter,
                                            blockingTaskExecutor, successFunction, requestAutoAbortDelayMillis,
                                            multipartUploadsLocation, multipartRemovalStrategy,
                                            serviceWorkerGroup, defaultHeaders,
                                            requestIdGenerator, defaultErrorHandler,
                                            unloggedExceptionsReporter, baseContextPath, contextHook);
                }).collect(toImmutableList());

        final ServiceConfig fallbackServiceConfig =
                new ServiceConfigBuilder(RouteBuilder.FALLBACK_ROUTE, "/", FallbackService.INSTANCE)
                        .build(defaultServiceNaming, defaultLogName, requestTimeoutMillis, maxRequestLength,
                               verboseResponses, accessLogWriter, blockingTaskExecutor, successFunction,
                               requestAutoAbortDelayMillis, multipartUploadsLocation, multipartRemovalStrategy,
                               serviceWorkerGroup, defaultHeaders, requestIdGenerator,
                               defaultErrorHandler, unloggedExceptionsReporter, "/", contextHook);

        final ImmutableList.Builder<ShutdownSupport> builder = ImmutableList.builder();
        builder.addAll(shutdownSupports);
        builder.addAll(template.shutdownSupports);

        final TlsEngineType tlsEngineType = this.tlsEngineType != null ?
                                            this.tlsEngineType : template.tlsEngineType;
        assert tlsEngineType != null;

        final SslContext sslContext = sslContext(template, tlsEngineType);
        if (sslContext != null && tlsProvider != null) {
            ReferenceCountUtil.release(sslContext);
            throw new IllegalStateException("Cannot configure TLS settings with a TlsProvider");
        }

        final VirtualHost virtualHost =
                new VirtualHost(defaultHostname, hostnamePattern, port,
                                sslContext, tlsProvider, tlsEngineType,
                                serviceConfigs, fallbackServiceConfig, rejectedRouteHandler,
                                accessLoggerMapper, defaultServiceNaming, defaultLogName, requestTimeoutMillis,
                                maxRequestLength, verboseResponses, accessLogWriter, blockingTaskExecutor,
                                requestAutoAbortDelayMillis, successFunction, multipartUploadsLocation,
                                multipartRemovalStrategy, serviceWorkerGroup, builder.build(),
                                requestIdGenerator);

        final Function<? super HttpService, ? extends HttpService> decorator =
                getRouteDecoratingService(template, baseContextPath);
        return decorator != null ? virtualHost.decorate(decorator) : virtualHost;
    }
Returns a newly-created {@link VirtualHost} based on the properties of this builder and the services
added to this builder.
core/src/main/java/com/linecorp/armeria/server/VirtualHostBuilder.java