/* * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.boot.web.reactive.context; import org.springframework.beans.BeansException; import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; import org.springframework.boot.web.server.WebServer; import org.springframework.context.ApplicationContextException; import org.springframework.http.server.reactive.HttpHandler; import org.springframework.util.StringUtils; /** * A {@link GenericReactiveWebApplicationContext} that can be used to bootstrap itself * from a contained {@link ReactiveWebServerFactory} bean. * * @author Brian Clozel * @since 2.0.0 */ public class ReactiveWebServerApplicationContext extends GenericReactiveWebApplicationContext { private volatile WebServer webServer; public ReactiveWebServerApplicationContext() { super(); } public ReactiveWebServerApplicationContext(Class<?>... annotatedClasses) { super(annotatedClasses); } @Override public final void refresh() throws BeansException, IllegalStateException { try { super.refresh(); } catch (RuntimeException ex) { stopAndReleaseReactiveWebServer(); throw ex; } } @Override protected void onRefresh() { super.onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start reactive web server", ex); } } @Override protected void finishRefresh() { super.finishRefresh(); WebServer localServer = startReactiveWebServer(); if (localServer != null) { publishEvent(new ReactiveWebServerInitializedEvent(localServer, this)); } } @Override protected void onClose() { super.onClose(); stopAndReleaseReactiveWebServer(); } private void createWebServer() { WebServer localServer = this.webServer; if (localServer == null) { this.webServer = getWebServerFactory().getWebServer(getHttpHandler()); } initPropertySources(); } /** * Return the {@link ReactiveWebServerFactory} that should be used to create the * reactive web server. By default this method searches for a suitable bean in the * context itself. * @return a {@link ReactiveWebServerFactory} (never {@code null}) */ protected ReactiveWebServerFactory getWebServerFactory() { // Use bean names so that we don't consider the hierarchy String[] beanNames = getBeanFactory() .getBeanNamesForType(ReactiveWebServerFactory.class); if (beanNames.length == 0) { throw new ApplicationContextException( "Unable to start ReactiveWebApplicationContext due to missing " + "ReactiveWebServerFactory bean."); } if (beanNames.length > 1) { throw new ApplicationContextException( "Unable to start ReactiveWebApplicationContext due to multiple " + "ReactiveWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames)); } return getBeanFactory().getBean(beanNames[0], ReactiveWebServerFactory.class); } /** * Return the {@link HttpHandler} that should be used to process the reactive web * server. By default this method searches for a suitable bean in the context itself. * @return a {@link HttpHandler} (never {@code null} */ protected HttpHandler getHttpHandler() { // Use bean names so that we don't consider the hierarchy String[] beanNames = getBeanFactory().getBeanNamesForType(HttpHandler.class); if (beanNames.length == 0) { throw new ApplicationContextException( "Unable to start ReactiveWebApplicationContext due to missing HttpHandler bean."); } if (beanNames.length > 1) { throw new ApplicationContextException( "Unable to start ReactiveWebApplicationContext due to multiple HttpHandler beans : " + StringUtils.arrayToCommaDelimitedString(beanNames)); } return getBeanFactory().getBean(beanNames[0], HttpHandler.class); } private WebServer startReactiveWebServer() { WebServer localServer = this.webServer; if (localServer != null) { localServer.start(); } return localServer; } private void stopAndReleaseReactiveWebServer() { WebServer localServer = this.webServer; if (localServer != null) { try { localServer.stop(); this.webServer = null; } catch (Exception ex) { throw new IllegalStateException(ex); } } } }