Merge branch '1.5.x'

pull/8103/merge
Phillip Webb 8 years ago
commit 17451c5e7a

@ -1,18 +1,19 @@
open_source_license.txt open_source_licenses.txt
Spring Boot CLI Spring Boot CLI
================================================================== ==================================================================
GoPivotal makes available all content in this download ("Content"). Pivotal makes available all content in this download ("Content").
Unless otherwise indicated below, the Content is provided to you under Unless otherwise indicated below, the Content is provided to you under
the terms and conditions of the Eclipse Public License Version 1.0 ("EPL"). the terms and conditions of the Apache License 2.0 (the "License"). A
A copy of the EPL is available in the file called license.txt. For copy of the license is available in the file called LICENSE.txt or you
purposes of the EPL, "Program" will mean the Content. may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
The following copyright statements and licenses apply to various open The following copyright statements and licenses apply to various open
source software packages (or portions thereof) that are distributed with source software packages (or portions thereof) that are distributed with
this Content. this content.
================================================================= =================================================================
@ -28,16 +29,43 @@ associated with each component.
SECTION 1: BSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES SECTION 1: BSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES
>>> antlr:antlr:2.7.7 >>> JLine (jline:jline)
>>> net.sf.jopt-simple:jopt-simple:4.5 >>> JOpt Simple (net.sf.jopt-simple:jopt-simple)
>>> org.ow2.asm:asm:4.1 >>> ASM 4.0 (org.ow2.asm:asm)
SECTION 2: Apache License, V2.0 SECTION 2: Apache License, V2.0
>>> org.codehaus.groovy:groovy:2.1 >>> JSON library from Android SDK (com.vaadin.external.google:android-json)
>>> org.apache.ivy:ivy:2.3.0 >>> Apache Commons Codec (commons-codec:commons-codec)
>>> Apache HttpClient (org.apache.httpcomponents:httpclient)
>>> Apache HttpCore (org.apache.httpcomponents:httpcore)
>>> Plexus Cipher: encryption/decryption Component (org.sonatype.plexus:plexus-cipher)
>>> Plexus Security Dispatcher Component (org.sonatype.plexus:plexus-sec-dispatcher)
>>> Apache Commons Logging (commons-logging:commons-logging)
>>> Apache Groovy (org.codehaus.groovy:groovy)
>>> Maven Aether Provider (org.apache.maven:maven-aether-provider)
>>> Maven Model (org.apache.maven:maven-model)
>>> Maven Model Builder (org.apache.maven:maven-model-builder)
>>> Maven Repository Metadata Model (org.apache.maven:maven-repository-metadata)
>>> Maven Settings (org.apache.maven:maven-settings)
>>> Maven Settings Builder (org.apache.maven:maven-settings-builder)
>>> Plexus :: Component Annotations (org.codehaus.plexus:plexus-component-annotations)
>>> Plexus Common Utilities (org.codehaus.plexus:plexus-utils)
>>> Plexus Component API (org.codehaus.plexus:plexus-component-api)
>>> Plexus Interpolation API (org.codehaus.plexus:plexus-interpolation)
SECTION 3: Eclipse Public License, Version 1.0
>>> Aether API (org.eclipse.aether:aether-api)
>>> Aether Connector Basic (org.eclipse.aether:aether-connector-basic)
>>> Aether Implementation (org.eclipse.aether:aether-impl)
>>> Aether SPI (org.eclipse.aether:aether-spi)
>>> Aether Transport File (org.eclipse.aether:aether-transport-file)
>>> Aether Transport HTTP (org.eclipse.aether:aether-transport-http)
>>> Aether Utilities (org.eclipse.aether:aether-util)
--------------- SECTION 1: BSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES ---------- --------------- SECTION 1: BSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES ----------
@ -45,38 +73,41 @@ SECTION 2: Apache License, V2.0
BSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES are applicable to the following component(s). BSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES are applicable to the following component(s).
>>> antlr:antlr:2.7.7 >>> JLine (jline:jline)
SOFTWARE RIGHTS
ANTLR 1989-2006 Developed by Terence Parr
Partially supported by University of San Francisco & jGuru.com
We reserve no legal rights to the ANTLR--it is fully in the
public domain. An individual or company may do whatever
they wish with source code distributed with ANTLR or the
code generated by ANTLR, including the incorporation of
ANTLR, or its output, into commerical software.
We encourage users to develop software with ANTLR. However, Copyright (c) 2002-2006, Marc Prud'hommeaux <mwp1@cornell.edu>
we do ask that credit is given to us for developing All rights reserved.
ANTLR. By "credit", we mean that if you use ANTLR or
incorporate any source code into one of your programs
(commercial product, research project, or otherwise) that
you acknowledge this fact somewhere in the documentation,
research report, etc... If you like ANTLR and have
developed a nice tool with the output, please mention that
you developed it using ANTLR. In addition, we ask that the
headers remain intact in our source code. As long as these
guidelines are kept, we expect to continue enhancing this
system and expect to make other tools available as they are
completed.
The primary ANTLR guy: Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the following
conditions are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with
the distribution.
Neither the name of JLine nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
Terence Parr
parrt@cs.usfca.edu
parrt@antlr.org
>>> net.sf.jopt-simple:jopt-simple:4.5 >>> net.sf.jopt-simple:jopt-simple:4.5
@ -103,7 +134,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
>>> org.ow2.asm:asm:4.1 >>> org.ow2.asm:asm
Copyright (c) 2000-2011 INRIA, France Telecom Copyright (c) 2000-2011 INRIA, France Telecom
All rights reserved. All rights reserved.
@ -136,12 +167,28 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE. THE POSSIBILITY OF SUCH DAMAGE.
--------------- SECTION 2: Apache License, V2.0 ---------- --------------- SECTION 2: Apache License, V2.0 ----------
Apache License, V2.0 is applicable to the following component(s). Apache License, V2.0 is applicable to the following component(s).
>>> org.codehaus.groovy:groovy:2.1 >>> org.apache.httpcomponents:httpclient
>>> org.apache.httpcomponents:httpcore
>>> org.sonatype.plexus:plexus-cipher
>>> org.sonatype.plexus:plexus-sec-dispatcher
>>> commons-logging:commons-logging
>>> org.codehaus.groovy:groovy
>>> org.apache.maven:maven-aether-provider
>>> org.apache.maven:maven-model
>>> org.apache.maven:maven-model-builder
>>> org.apache.maven:maven-repository-metadata
>>> org.apache.maven:maven-settings
>>> org.apache.maven:maven-settings-builder
>>> org.codehaus.plexus:plexus-component-annotations
>>> org.codehaus.plexus:plexus-utils
>>> org.codehaus.plexus:plexus-component-api
>>> org.codehaus.plexus:plexus-interpolation
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -155,22 +202,58 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License limitations under the License
>>> CGLIB 3.0 (cglib:cglib:3.0):
>>> org.apache.ivy:ivy:2.3.0 Per the LICENSE file in the CGLIB JAR distribution downloaded from
http://sourceforge.net/projects/cglib/files/cglib3/3.0/cglib-3.0.jar/download,
CGLIB 3.0 is licensed under the Apache License, version 2.0, the text of which
is included above.
Copyright (c) 2007-2013 The Apache Software Foundation
Licensed under the Apache License, Version 2.0 (the "License"); --------------- SECTION 3: Eclipse Public License, Version 1.0 ----------
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 Eclipse Public License, Version 1.0 is applicable to the following component(s).
>>> org.eclipse.aether:aether-api
>>> org.eclipse.aether:aether-connector-basic
>>> org.eclipse.aether:aether-impl
>>> org.eclipse.aether:aether-spi
>>> org.eclipse.aether:aether-transport-file
>>> org.eclipse.aether:aether-transport-http
>>> org.eclipse.aether:aether-util
The Eclipse Foundation makes available all content in this plug-in ("Content").
Unless otherwise indicated below, the Content is provided to you under the terms
and conditions of the Eclipse Public License Version 1.0 ("EPL"). A copy of the
EPL is available at http://www.eclipse.org/legal/epl-v10.html.
For purposes of the EPL, "Program" will mean the Content.
If you did not receive this Content directly from the Eclipse Foundation, the
Content is being redistributed by another party ("Redistributor") and different
terms and conditions may apply to your use of any object code in the Content.
Check the Redistributor's license that was provided with the Content. If no such
license exists, contact the Redistributor. Unless otherwise indicated below, the
terms and conditions of the EPL still apply to any source code in the Content and
such source code may be obtained at http://www.eclipse.org/
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
=========================================================================== ===========================================================================
To the extent any open source subcomponents are licensed under the EPL and/or
other similar licenses that require the source code and/or modifications to
source code to be made available (as would be noted above), you may obtain a
copy of the source code corresponding to the binaries for such open source
components and modifications thereto, if any, (the "Source Files"), by
downloading the Source Files from https://github.com/spring-projects/spring-boot,
or by sending a request, with your name and address to:
Pivotal, Inc., 875 Howard St,
San Francisco, CA 94103
United States of America
or email info@pivotal.io. All such requests should clearly specify:
OPEN SOURCE FILES REQUEST
Attention General Counsel

@ -1489,11 +1489,10 @@ You can apply the same principle if you are configuring a custom JNDI `DataSourc
} }
---- ----
Spring Boot also provides a utility builder class `DataSourceBuilder` that can be used to
Spring Boot also provides a utility builder class `DataSourceBuilder` that can be used create one of the standard data sources (if it is on the classpath). The builder can
to create one of the standard data sources (if it is on the classpath). The builder can detect the one to use based on what's available on the classpath. It also auto detects the
detect the one to use based on the ones available on the classpath and it also auto driver based on the JDBC url.
detects the driver based on the JDBC url.
[source,java,indent=0,subs="verbatim,quotes,attributes"] [source,java,indent=0,subs="verbatim,quotes,attributes"]
---- ----
@ -1516,7 +1515,7 @@ There is a catch however. Because the actual type of the connection pool is not
no keys are generated in the metadata for your custom `DataSource` and no completion is no keys are generated in the metadata for your custom `DataSource` and no completion is
available in your IDE (The `DataSource` interface doesn't expose any property). Also, if available in your IDE (The `DataSource` interface doesn't expose any property). Also, if
you happen to _only_ have Hikari on the classpath, this basic setup will not work because you happen to _only_ have Hikari on the classpath, this basic setup will not work because
Hikari has no `url` parameter (but a `jdbcUrl` parameter). You should have to rewrite Hikari has no `url` parameter (but a `jdbcUrl` parameter). You will have to rewrite
your configuration as follows: your configuration as follows:
[source,properties,indent=0] [source,properties,indent=0]
@ -1618,6 +1617,7 @@ This final example configures two data sources on custom namespaces with the sam
than what Spring Boot would do in auto-configuration. than what Spring Boot would do in auto-configuration.
[[howto-use-spring-data-repositories]] [[howto-use-spring-data-repositories]]
=== Use Spring Data repositories === Use Spring Data repositories
Spring Data can create implementations for you of `@Repository` interfaces of various Spring Data can create implementations for you of `@Repository` interfaces of various

@ -45,4 +45,5 @@ public class BasicDataSourceExample {
// end::configuration[] // end::configuration[]
} }
} }

@ -25,8 +25,8 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
/** /**
* Example configuration for configuring two data sources with what Spring Boot does * Example configuration for configuring two data sources with what Spring Boot does in
* in auto-configuration. * auto-configuration.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
@ -50,9 +50,7 @@ public class CompleteTwoDataSourcesExample {
@Primary @Primary
@ConfigurationProperties("app.datasource.foo") @ConfigurationProperties("app.datasource.foo")
public DataSource fooDataSource() { public DataSource fooDataSource() {
return fooDataSourceProperties() return fooDataSourceProperties().initializeDataSourceBuilder().build();
.initializeDataSourceBuilder()
.build();
} }
@Bean @Bean
@ -61,13 +59,10 @@ public class CompleteTwoDataSourcesExample {
return new DataSourceProperties(); return new DataSourceProperties();
} }
@Bean @Bean
@ConfigurationProperties("app.datasource.bar") @ConfigurationProperties("app.datasource.bar")
public DataSource barDataSource() { public DataSource barDataSource() {
return barDataSourceProperties() return barDataSourceProperties().initializeDataSourceBuilder().build();
.initializeDataSourceBuilder()
.build();
} }
// end::configuration[] // end::configuration[]

@ -52,10 +52,10 @@ public class ConfigurableDataSourceExample {
@ConfigurationProperties("app.datasource") @ConfigurationProperties("app.datasource")
public HikariDataSource dataSource(DataSourceProperties properties) { public HikariDataSource dataSource(DataSourceProperties properties) {
return (HikariDataSource) properties.initializeDataSourceBuilder() return (HikariDataSource) properties.initializeDataSourceBuilder()
.type(HikariDataSource.class) .type(HikariDataSource.class).build();
.build();
} }
// end::configuration[] // end::configuration[]
} }
} }

@ -43,8 +43,7 @@ public class SimpleDataSourceExample {
@ConfigurationProperties("app.datasource") @ConfigurationProperties("app.datasource")
public HikariDataSource dataSource() { public HikariDataSource dataSource() {
return (HikariDataSource) DataSourceBuilder.create() return (HikariDataSource) DataSourceBuilder.create()
.type(HikariDataSource.class) .type(HikariDataSource.class).build();
.build();
} }
// end::configuration[] // end::configuration[]

@ -53,18 +53,14 @@ public class SimpleTwoDataSourcesExample {
@Primary @Primary
@ConfigurationProperties("app.datasource.foo") @ConfigurationProperties("app.datasource.foo")
public DataSource fooDataSource() { public DataSource fooDataSource() {
return fooDataSourceProperties() return fooDataSourceProperties().initializeDataSourceBuilder().build();
.initializeDataSourceBuilder()
.build();
} }
@Bean @Bean
@ConfigurationProperties("app.datasource.bar") @ConfigurationProperties("app.datasource.bar")
public BasicDataSource barDataSource() { public BasicDataSource barDataSource() {
return (BasicDataSource) DataSourceBuilder.create() return (BasicDataSource) DataSourceBuilder.create()
.type(BasicDataSource.class) .type(BasicDataSource.class).build();
.build();
} }
// end::configuration[] // end::configuration[]

@ -33,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Test for {@link BasicDataSourceExample}. * Test for {@link BasicDataSourceExample}.
*
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)

@ -47,12 +47,10 @@ public class CompleteTwoDataSourcesExampleTests {
@Test @Test
public void validateConfiguration() throws SQLException { public void validateConfiguration() throws SQLException {
assertThat(this.context.getBeansOfType(DataSource.class)).hasSize(2); assertThat(this.context.getBeansOfType(DataSource.class)).hasSize(2);
DataSource dataSource = this.context.getBean(DataSource.class); DataSource dataSource = this.context.getBean(DataSource.class);
assertThat(this.context.getBean("fooDataSource")).isSameAs(dataSource); assertThat(this.context.getBean("fooDataSource")).isSameAs(dataSource);
assertThat(dataSource.getConnection().getMetaData().getURL()) assertThat(dataSource.getConnection().getMetaData().getURL())
.startsWith("jdbc:h2:mem:"); .startsWith("jdbc:h2:mem:");
DataSource barDataSource = this.context.getBean("barDataSource", DataSource barDataSource = this.context.getBean("barDataSource",
DataSource.class); DataSource.class);
assertThat(barDataSource.getConnection().getMetaData().getURL()) assertThat(barDataSource.getConnection().getMetaData().getURL())

@ -23,8 +23,8 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/** /**
* A sample {@link SpringBootConfiguration} that only enables the auto-configuration * A sample {@link SpringBootConfiguration} that only enables the auto-configuration for
* for the {@link DataSource}. * the {@link DataSource}.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */

@ -38,8 +38,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(properties = { @SpringBootTest(properties = { "app.datasource.bar.url=jdbc:h2:mem:bar;DB_CLOSE_DELAY=-1",
"app.datasource.bar.url=jdbc:h2:mem:bar;DB_CLOSE_DELAY=-1",
"app.datasource.bar.max-total=42" }) "app.datasource.bar.max-total=42" })
@Import(SimpleTwoDataSourcesExample.SimpleDataSourcesConfiguration.class) @Import(SimpleTwoDataSourcesExample.SimpleDataSourcesConfiguration.class)
public class SimpleTwoDataSourcesExampleTests { public class SimpleTwoDataSourcesExampleTests {
@ -50,16 +49,13 @@ public class SimpleTwoDataSourcesExampleTests {
@Test @Test
public void validateConfiguration() throws SQLException { public void validateConfiguration() throws SQLException {
assertThat(this.context.getBeansOfType(DataSource.class)).hasSize(2); assertThat(this.context.getBeansOfType(DataSource.class)).hasSize(2);
DataSource dataSource = this.context.getBean(DataSource.class); DataSource dataSource = this.context.getBean(DataSource.class);
assertThat(this.context.getBean("fooDataSource")).isSameAs(dataSource); assertThat(this.context.getBean("fooDataSource")).isSameAs(dataSource);
assertThat(dataSource.getConnection().getMetaData().getURL()) assertThat(dataSource.getConnection().getMetaData().getURL())
.startsWith("jdbc:h2:mem:"); .startsWith("jdbc:h2:mem:");
BasicDataSource barDataSource = this.context.getBean("barDataSource", BasicDataSource barDataSource = this.context.getBean("barDataSource",
BasicDataSource.class); BasicDataSource.class);
assertThat(barDataSource.getUrl()) assertThat(barDataSource.getUrl()).isEqualTo("jdbc:h2:mem:bar;DB_CLOSE_DELAY=-1");
.isEqualTo("jdbc:h2:mem:bar;DB_CLOSE_DELAY=-1");
assertThat(barDataSource.getMaxTotal()).isEqualTo(42); assertThat(barDataSource.getMaxTotal()).isEqualTo(42);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2016 the original author or authors. * Copyright 2012-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -1252,7 +1252,6 @@ public class SpringApplication {
finally { finally {
close(context); close(context);
} }
} }
catch (Exception ex) { catch (Exception ex) {
ex.printStackTrace(); ex.printStackTrace();

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@
package org.springframework.boot.context.config; package org.springframework.boot.context.config;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
@ -70,8 +71,11 @@ public class DelegatingApplicationListener
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private List<ApplicationListener<ApplicationEvent>> getListeners( private List<ApplicationListener<ApplicationEvent>> getListeners(
ConfigurableEnvironment env) { ConfigurableEnvironment environment) {
String classNames = env.getProperty(PROPERTY_NAME); if (environment == null) {
return Collections.emptyList();
}
String classNames = environment.getProperty(PROPERTY_NAME);
List<ApplicationListener<ApplicationEvent>> listeners = new ArrayList<ApplicationListener<ApplicationEvent>>(); List<ApplicationListener<ApplicationEvent>> listeners = new ArrayList<ApplicationListener<ApplicationEvent>>();
if (StringUtils.hasLength(classNames)) { if (StringUtils.hasLength(classNames)) {
for (String className : StringUtils.commaDelimitedListToSet(classNames)) { for (String className : StringUtils.commaDelimitedListToSet(classNames)) {

@ -59,6 +59,8 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
private Connector[] connectors; private Connector[] connectors;
private volatile boolean started;
/** /**
* Create a new {@link JettyEmbeddedServletContainer} instance. * Create a new {@link JettyEmbeddedServletContainer} instance.
* @param server the underlying Jetty server * @param server the underlying Jetty server
@ -111,6 +113,10 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
@Override @Override
public void start() throws EmbeddedServletContainerException { public void start() throws EmbeddedServletContainerException {
synchronized (this.monitor) {
if (this.started) {
return;
}
this.server.setConnectors(this.connectors); this.server.setConnectors(this.connectors);
if (!this.autoStart) { if (!this.autoStart) {
return; return;
@ -133,6 +139,7 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
throw ex; throw ex;
} }
} }
this.started = true;
JettyEmbeddedServletContainer.logger JettyEmbeddedServletContainer.logger
.info("Jetty started on port(s) " + getActualPortsDescription()); .info("Jetty started on port(s) " + getActualPortsDescription());
} }
@ -144,6 +151,7 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
"Unable to start embedded Jetty servlet container", ex); "Unable to start embedded Jetty servlet container", ex);
} }
} }
}
private String getActualPortsDescription() { private String getActualPortsDescription() {
StringBuilder ports = new StringBuilder(); StringBuilder ports = new StringBuilder();
@ -197,6 +205,10 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
@Override @Override
public void stop() { public void stop() {
synchronized (this.monitor) { synchronized (this.monitor) {
if (!this.started) {
return;
}
this.started = false;
try { try {
this.server.stop(); this.server.stop();
} }

@ -62,6 +62,8 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
private final boolean autoStart; private final boolean autoStart;
private volatile boolean started;
/** /**
* Create a new {@link TomcatEmbeddedServletContainer} instance. * Create a new {@link TomcatEmbeddedServletContainer} instance.
* @param tomcat the underlying Tomcat server * @param tomcat the underlying Tomcat server
@ -174,6 +176,10 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
@Override @Override
public void start() throws EmbeddedServletContainerException { public void start() throws EmbeddedServletContainerException {
synchronized (this.monitor) {
if (this.started) {
return;
}
try { try {
addPreviouslyRemovedConnectors(); addPreviouslyRemovedConnectors();
Connector connector = this.tomcat.getConnector(); Connector connector = this.tomcat.getConnector();
@ -181,6 +187,7 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
startConnector(connector); startConnector(connector);
} }
checkThatConnectorsHaveStarted(); checkThatConnectorsHaveStarted();
this.started = true;
TomcatEmbeddedServletContainer.logger TomcatEmbeddedServletContainer.logger
.info("Tomcat started on port(s): " + getPortsDescription(true)); .info("Tomcat started on port(s): " + getPortsDescription(true));
} }
@ -198,6 +205,7 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
getClass().getClassLoader()); getClass().getClassLoader());
} }
} }
}
private void checkThatConnectorsHaveStarted() { private void checkThatConnectorsHaveStarted() {
for (Connector connector : this.tomcat.getService().findConnectors()) { for (Connector connector : this.tomcat.getService().findConnectors()) {
@ -271,7 +279,11 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
@Override @Override
public void stop() throws EmbeddedServletContainerException { public void stop() throws EmbeddedServletContainerException {
synchronized (this.monitor) { synchronized (this.monitor) {
if (!this.started) {
return;
}
try { try {
this.started = false;
try { try {
stopTomcat(); stopTomcat();
this.tomcat.destroy(); this.tomcat.destroy();

@ -88,7 +88,7 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
private Undertow undertow; private Undertow undertow;
private boolean started = false; private volatile boolean started = false;
/** /**
* Create a new {@link UndertowEmbeddedServletContainer} instance. * Create a new {@link UndertowEmbeddedServletContainer} instance.
@ -144,6 +144,9 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
@Override @Override
public void start() throws EmbeddedServletContainerException { public void start() throws EmbeddedServletContainerException {
synchronized (this.monitor) { synchronized (this.monitor) {
if (this.started) {
return;
}
try { try {
if (!this.autoStart) { if (!this.autoStart) {
return; return;
@ -305,9 +308,11 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
@Override @Override
public void stop() throws EmbeddedServletContainerException { public void stop() throws EmbeddedServletContainerException {
synchronized (this.monitor) { synchronized (this.monitor) {
if (this.started) { if (!this.started) {
try { return;
}
this.started = false; this.started = false;
try {
this.manager.stop(); this.manager.stop();
this.undertow.stop(); this.undertow.stop();
} }
@ -317,7 +322,6 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
} }
} }
} }
}
@Override @Override
public int getPort() { public int getPort() {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2016 the original author or authors. * Copyright 2012-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,9 @@
package org.springframework.boot.context.event; package org.springframework.boot.context.event;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener; import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
@ -25,6 +28,7 @@ import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster; import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.ErrorHandler;
/** /**
* {@link SpringApplicationRunListener} to publish {@link SpringApplicationEvent}s. * {@link SpringApplicationRunListener} to publish {@link SpringApplicationEvent}s.
@ -41,7 +45,7 @@ public class EventPublishingRunListener implements SpringApplicationRunListener,
private final String[] args; private final String[] args;
private final ApplicationEventMulticaster initialMulticaster; private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) { public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application; this.application = application;
@ -89,9 +93,18 @@ public class EventPublishingRunListener implements SpringApplicationRunListener,
@Override @Override
public void finished(ConfigurableApplicationContext context, Throwable exception) { public void finished(ConfigurableApplicationContext context, Throwable exception) {
SpringApplicationEvent event = getFinishedEvent(context, exception);
if (context != null) {
// Listeners have been registered to the application context so we should // Listeners have been registered to the application context so we should
// use it at this point // use it at this point if we can
context.publishEvent(getFinishedEvent(context, exception)); context.publishEvent(event);
}
else {
if (event instanceof ApplicationFailedEvent) {
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
}
this.initialMulticaster.multicastEvent(event);
}
} }
private SpringApplicationEvent getFinishedEvent( private SpringApplicationEvent getFinishedEvent(
@ -103,4 +116,15 @@ public class EventPublishingRunListener implements SpringApplicationRunListener,
return new ApplicationReadyEvent(this.application, this.args, context); return new ApplicationReadyEvent(this.application, this.args, context);
} }
private static class LoggingErrorHandler implements ErrorHandler {
private static Log logger = LogFactory.getLog(EventPublishingRunListener.class);
@Override
public void handleError(Throwable throwable) {
logger.warn("Error calling ApplicationEventListener", throwable);
}
}
} }

@ -0,0 +1,23 @@
/*
* 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.env;
/**
* @author pwebb
*/
public interface DunnoEnumerablePropertySource {
}

@ -0,0 +1,28 @@
/*
* 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.env;
/**
* @author pwebb
*/
public interface DunnoPropertySource {
boolean containsProperty(String name);
Object getProperty(String name);
}

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2016 the original author or authors. * Copyright 2012-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -167,7 +167,7 @@ public class LoggingApplicationListener implements GenericApplicationListener {
private static Class<?>[] EVENT_TYPES = { ApplicationStartingEvent.class, private static Class<?>[] EVENT_TYPES = { ApplicationStartingEvent.class,
ApplicationEnvironmentPreparedEvent.class, ApplicationPreparedEvent.class, ApplicationEnvironmentPreparedEvent.class, ApplicationPreparedEvent.class,
ContextClosedEvent.class }; ContextClosedEvent.class, ApplicationFailedEvent.class };
private static Class<?>[] SOURCE_TYPES = { SpringApplication.class, private static Class<?>[] SOURCE_TYPES = { SpringApplication.class,
ApplicationContext.class }; ApplicationContext.class };

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2016 the original author or authors. * Copyright 2012-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -251,6 +251,7 @@ public class Log4J2LoggingSystem extends Slf4JLoggingSystem {
super.cleanUp(); super.cleanUp();
LoggerContext loggerContext = getLoggerContext(); LoggerContext loggerContext = getLoggerContext();
markAsUninitialized(loggerContext); markAsUninitialized(loggerContext);
loggerContext.getConfiguration().removeFilter(FILTER);
} }
private LoggerConfig getLoggerConfig(String name) { private LoggerConfig getLoggerConfig(String name) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2016 the original author or authors. * Copyright 2012-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -193,9 +193,11 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
@Override @Override
public void cleanUp() { public void cleanUp() {
markAsUninitialized(getLoggerContext()); LoggerContext context = getLoggerContext();
markAsUninitialized(context);
super.cleanUp(); super.cleanUp();
getLoggerContext().getStatusManager().clear(); context.getStatusManager().clear();
context.getTurboFilterList().remove(FILTER);
} }
@Override @Override

@ -82,6 +82,7 @@ import org.mockito.InOrder;
import org.springframework.boot.ApplicationHome; import org.springframework.boot.ApplicationHome;
import org.springframework.boot.ApplicationTemp; import org.springframework.boot.ApplicationTemp;
import org.springframework.boot.context.embedded.Ssl.ClientAuth; import org.springframework.boot.context.embedded.Ssl.ClientAuth;
import org.springframework.boot.testutil.InternalOutputCapture;
import org.springframework.boot.web.servlet.ErrorPage; import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.boot.web.servlet.ServletContextInitializer;
@ -124,6 +125,9 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
@Rule @Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder(); public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Rule
public InternalOutputCapture output = new InternalOutputCapture();
protected EmbeddedServletContainer container; protected EmbeddedServletContainer container;
private final HttpClientContext httpClientContext = HttpClientContext.create(); private final HttpClientContext httpClientContext = HttpClientContext.create();
@ -157,6 +161,19 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
assertThat(getResponse(getLocalUrl("/hello"))).isEqualTo("Hello World"); assertThat(getResponse(getLocalUrl("/hello"))).isEqualTo("Hello World");
} }
@Test
public void startCalledTwice() throws Exception {
AbstractEmbeddedServletContainerFactory factory = getFactory();
this.container = factory
.getEmbeddedServletContainer(exampleServletRegistration());
this.container.start();
int port = this.container.getPort();
this.container.start();
assertThat(this.container.getPort()).isEqualTo(port);
assertThat(getResponse(getLocalUrl("/hello"))).isEqualTo("Hello World");
assertThat(this.output.toString()).containsOnlyOnce("started on port");
}
@Test @Test
public void emptyServerWhenPortIsMinusOne() throws Exception { public void emptyServerWhenPortIsMinusOne() throws Exception {
AbstractEmbeddedServletContainerFactory factory = getFactory(); AbstractEmbeddedServletContainerFactory factory = getFactory();

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2016 the original author or authors. * Copyright 2012-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -42,7 +42,10 @@ import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent; import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.boot.logging.java.JavaLoggingSystem; import org.springframework.boot.logging.java.JavaLoggingSystem;
import org.springframework.boot.testutil.InternalOutputCapture; import org.springframework.boot.testutil.InternalOutputCapture;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.context.support.GenericApplicationContext; import org.springframework.context.support.GenericApplicationContext;
import org.springframework.test.context.support.TestPropertySourceUtils; import org.springframework.test.context.support.TestPropertySourceUtils;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
@ -85,8 +88,7 @@ public class LoggingApplicationListenerTests {
public void init() throws SecurityException, IOException { public void init() throws SecurityException, IOException {
LogManager.getLogManager().readConfiguration( LogManager.getLogManager().readConfiguration(
JavaLoggingSystem.class.getResourceAsStream("logging.properties")); JavaLoggingSystem.class.getResourceAsStream("logging.properties"));
this.initializer.onApplicationEvent( multicastEvent(new ApplicationStartingEvent(new SpringApplication(), NO_ARGS));
new ApplicationStartingEvent(new SpringApplication(), NO_ARGS));
new File("target/foo.log").delete(); new File("target/foo.log").delete();
new File(tmpDir() + "/spring.log").delete(); new File(tmpDir() + "/spring.log").delete();
} }
@ -354,8 +356,8 @@ public class LoggingApplicationListenerTests {
public void parseArgsDoesntReplace() throws Exception { public void parseArgsDoesntReplace() throws Exception {
this.initializer.setSpringBootLogging(LogLevel.ERROR); this.initializer.setSpringBootLogging(LogLevel.ERROR);
this.initializer.setParseArgs(false); this.initializer.setParseArgs(false);
this.initializer.onApplicationEvent(new ApplicationStartingEvent( multicastEvent(new ApplicationStartingEvent(this.springApplication,
this.springApplication, new String[] { "--debug" })); new String[] { "--debug" }));
this.initializer.initialize(this.context.getEnvironment(), this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader()); this.context.getClassLoader());
this.logger.debug("testatdebug"); this.logger.debug("testatdebug");
@ -365,7 +367,7 @@ public class LoggingApplicationListenerTests {
@Test @Test
public void bridgeHandlerLifecycle() throws Exception { public void bridgeHandlerLifecycle() throws Exception {
assertThat(bridgeHandlerInstalled()).isTrue(); assertThat(bridgeHandlerInstalled()).isTrue();
this.initializer.onApplicationEvent(new ContextClosedEvent(this.context)); multicastEvent(new ContextClosedEvent(this.context));
assertThat(bridgeHandlerInstalled()).isFalse(); assertThat(bridgeHandlerInstalled()).isFalse();
} }
@ -398,7 +400,7 @@ public class LoggingApplicationListenerTests {
TestLoggingApplicationListener listener = new TestLoggingApplicationListener(); TestLoggingApplicationListener listener = new TestLoggingApplicationListener();
System.setProperty(LoggingSystem.class.getName(), System.setProperty(LoggingSystem.class.getName(),
TestShutdownHandlerLoggingSystem.class.getName()); TestShutdownHandlerLoggingSystem.class.getName());
listener.onApplicationEvent( multicastEvent(listener,
new ApplicationStartingEvent(new SpringApplication(), NO_ARGS)); new ApplicationStartingEvent(new SpringApplication(), NO_ARGS));
listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); listener.initialize(this.context.getEnvironment(), this.context.getClassLoader());
assertThat(listener.shutdownHook).isNull(); assertThat(listener.shutdownHook).isNull();
@ -411,7 +413,7 @@ public class LoggingApplicationListenerTests {
TestShutdownHandlerLoggingSystem.class.getName()); TestShutdownHandlerLoggingSystem.class.getName());
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"logging.register_shutdown_hook=true"); "logging.register_shutdown_hook=true");
listener.onApplicationEvent( multicastEvent(listener,
new ApplicationStartingEvent(new SpringApplication(), NO_ARGS)); new ApplicationStartingEvent(new SpringApplication(), NO_ARGS));
listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); listener.initialize(this.context.getEnvironment(), this.context.getClassLoader());
assertThat(listener.shutdownHook).isNotNull(); assertThat(listener.shutdownHook).isNotNull();
@ -424,12 +426,12 @@ public class LoggingApplicationListenerTests {
public void closingContextCleansUpLoggingSystem() { public void closingContextCleansUpLoggingSystem() {
System.setProperty(LoggingSystem.SYSTEM_PROPERTY, System.setProperty(LoggingSystem.SYSTEM_PROPERTY,
TestCleanupLoggingSystem.class.getName()); TestCleanupLoggingSystem.class.getName());
this.initializer.onApplicationEvent( multicastEvent(
new ApplicationStartingEvent(this.springApplication, new String[0])); new ApplicationStartingEvent(this.springApplication, new String[0]));
TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils
.getField(this.initializer, "loggingSystem"); .getField(this.initializer, "loggingSystem");
assertThat(loggingSystem.cleanedUp).isFalse(); assertThat(loggingSystem.cleanedUp).isFalse();
this.initializer.onApplicationEvent(new ContextClosedEvent(this.context)); multicastEvent(new ContextClosedEvent(this.context));
assertThat(loggingSystem.cleanedUp).isTrue(); assertThat(loggingSystem.cleanedUp).isTrue();
} }
@ -437,16 +439,16 @@ public class LoggingApplicationListenerTests {
public void closingChildContextDoesNotCleanUpLoggingSystem() { public void closingChildContextDoesNotCleanUpLoggingSystem() {
System.setProperty(LoggingSystem.SYSTEM_PROPERTY, System.setProperty(LoggingSystem.SYSTEM_PROPERTY,
TestCleanupLoggingSystem.class.getName()); TestCleanupLoggingSystem.class.getName());
this.initializer.onApplicationEvent( multicastEvent(
new ApplicationStartingEvent(this.springApplication, new String[0])); new ApplicationStartingEvent(this.springApplication, new String[0]));
TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils
.getField(this.initializer, "loggingSystem"); .getField(this.initializer, "loggingSystem");
assertThat(loggingSystem.cleanedUp).isFalse(); assertThat(loggingSystem.cleanedUp).isFalse();
GenericApplicationContext childContext = new GenericApplicationContext(); GenericApplicationContext childContext = new GenericApplicationContext();
childContext.setParent(this.context); childContext.setParent(this.context);
this.initializer.onApplicationEvent(new ContextClosedEvent(childContext)); multicastEvent(new ContextClosedEvent(childContext));
assertThat(loggingSystem.cleanedUp).isFalse(); assertThat(loggingSystem.cleanedUp).isFalse();
this.initializer.onApplicationEvent(new ContextClosedEvent(this.context)); multicastEvent(new ContextClosedEvent(this.context));
assertThat(loggingSystem.cleanedUp).isTrue(); assertThat(loggingSystem.cleanedUp).isTrue();
childContext.close(); childContext.close();
} }
@ -493,17 +495,26 @@ public class LoggingApplicationListenerTests {
public void applicationFailedEventCleansUpLoggingSystem() { public void applicationFailedEventCleansUpLoggingSystem() {
System.setProperty(LoggingSystem.SYSTEM_PROPERTY, System.setProperty(LoggingSystem.SYSTEM_PROPERTY,
TestCleanupLoggingSystem.class.getName()); TestCleanupLoggingSystem.class.getName());
this.initializer.onApplicationEvent( multicastEvent(
new ApplicationStartingEvent(this.springApplication, new String[0])); new ApplicationStartingEvent(this.springApplication, new String[0]));
TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils
.getField(this.initializer, "loggingSystem"); .getField(this.initializer, "loggingSystem");
assertThat(loggingSystem.cleanedUp).isFalse(); assertThat(loggingSystem.cleanedUp).isFalse();
this.initializer multicastEvent(new ApplicationFailedEvent(this.springApplication, new String[0],
.onApplicationEvent(new ApplicationFailedEvent(this.springApplication, new GenericApplicationContext(), new Exception()));
new String[0], new GenericApplicationContext(), new Exception()));
assertThat(loggingSystem.cleanedUp).isTrue(); assertThat(loggingSystem.cleanedUp).isTrue();
} }
private void multicastEvent(ApplicationEvent event) {
multicastEvent(this.initializer, event);
}
private void multicastEvent(ApplicationListener<?> listener, ApplicationEvent event) {
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
multicaster.addApplicationListener(listener);
multicaster.multicastEvent(event);
}
private boolean bridgeHandlerInstalled() { private boolean bridgeHandlerInstalled() {
Logger rootLogger = LogManager.getLogManager().getLogger(""); Logger rootLogger = LogManager.getLogManager().getLogger("");
Handler[] handlers = rootLogger.getHandlers(); Handler[] handlers = rootLogger.getHandlers();

Loading…
Cancel
Save