diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/LoggingApplicationListener.java b/spring-boot/src/main/java/org/springframework/boot/logging/LoggingApplicationListener.java
index 29f56931d6e..2f6ae29e7cc 100644
--- a/spring-boot/src/main/java/org/springframework/boot/logging/LoggingApplicationListener.java
+++ b/spring-boot/src/main/java/org/springframework/boot/logging/LoggingApplicationListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2014 the original author or authors.
+ * Copyright 2012-2015 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.
@@ -28,8 +28,10 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationStartedEvent;
+import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
@@ -68,6 +70,7 @@ import org.springframework.util.StringUtils;
*
* @author Dave Syer
* @author Phillip Webb
+ * @author Andy Wilkinson
*/
public class LoggingApplicationListener implements SmartApplicationListener {
@@ -115,7 +118,10 @@ public class LoggingApplicationListener implements SmartApplicationListener {
}
private static Class>[] EVENT_TYPES = { ApplicationStartedEvent.class,
- ApplicationEnvironmentPreparedEvent.class };
+ ApplicationEnvironmentPreparedEvent.class, ContextClosedEvent.class };
+
+ private static Class>[] SOURCE_TYPES = { SpringApplication.class,
+ ApplicationContext.class };
private final Log logger = LogFactory.getLog(getClass());
@@ -127,17 +133,21 @@ public class LoggingApplicationListener implements SmartApplicationListener {
@Override
public boolean supportsEventType(Class extends ApplicationEvent> eventType) {
- for (Class> type : EVENT_TYPES) {
- if (type.isAssignableFrom(eventType)) {
- return true;
- }
- }
- return false;
+ return isAssignableFrom(eventType, EVENT_TYPES);
}
@Override
public boolean supportsSourceType(Class> sourceType) {
- return SpringApplication.class.isAssignableFrom(sourceType);
+ return isAssignableFrom(sourceType, SOURCE_TYPES);
+ }
+
+ private boolean isAssignableFrom(Class> type, Class>[] supportedTypes) {
+ for (Class> supportedType : supportedTypes) {
+ if (supportedType.isAssignableFrom(type)) {
+ return true;
+ }
+ }
+ return false;
}
@Override
@@ -147,7 +157,7 @@ public class LoggingApplicationListener implements SmartApplicationListener {
initialize(available.getEnvironment(), available.getSpringApplication()
.getClassLoader());
}
- else {
+ else if (event instanceof ApplicationStartedEvent) {
if (System.getProperty(PID_KEY) == null) {
System.setProperty(PID_KEY, new ApplicationPid().toString());
}
@@ -155,6 +165,11 @@ public class LoggingApplicationListener implements SmartApplicationListener {
.getDefaultClassLoader());
loggingSystem.beforeInitialize();
}
+ else {
+ LoggingSystem loggingSystem = LoggingSystem.get(ClassUtils
+ .getDefaultClassLoader());
+ loggingSystem.cleanUp();
+ }
}
/**
diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java
index 469ec1dde38..4749609bf6c 100644
--- a/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java
+++ b/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2013 the original author or authors.
+ * Copyright 2012-2015 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.
@@ -27,6 +27,7 @@ import org.springframework.util.ClassUtils;
*
* @author Phillip Webb
* @author Dave Syer
+ * @author Andy Wilkinson
*/
public abstract class LoggingSystem {
@@ -61,6 +62,14 @@ public abstract class LoggingSystem {
*/
public abstract void initialize(String configLocation);
+ /**
+ * Clean up the logging system. The default implementation does nothing. Subclasses
+ * should override this method to perform any logging system-specific cleanup.
+ */
+ public void cleanUp() {
+
+ }
+
/**
* Sets the logging level for a given logger.
* @param loggerName the name of the logger to set
diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/log4j/Log4JLoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/log4j/Log4JLoggingSystem.java
index bd7a83bec6b..1fed364f028 100644
--- a/spring-boot/src/main/java/org/springframework/boot/logging/log4j/Log4JLoggingSystem.java
+++ b/spring-boot/src/main/java/org/springframework/boot/logging/log4j/Log4JLoggingSystem.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2013 the original author or authors.
+ * Copyright 2012-2015 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.
@@ -37,6 +37,7 @@ import org.springframework.util.StringUtils;
*
* @author Phillip Webb
* @author Dave Syer
+ * @author Andy Wilkinson
*/
public class Log4JLoggingSystem extends AbstractLoggingSystem {
@@ -60,10 +61,7 @@ public class Log4JLoggingSystem extends AbstractLoggingSystem {
@Override
public void beforeInitialize() {
super.beforeInitialize();
- if (ClassUtils.isPresent("org.slf4j.bridge.SLF4JBridgeHandler", getClassLoader())) {
- SLF4JBridgeHandler.removeHandlersForRootLogger();
- SLF4JBridgeHandler.install();
- }
+ configureJdkLoggingBridgeHandler();
}
@Override
@@ -78,6 +76,45 @@ public class Log4JLoggingSystem extends AbstractLoggingSystem {
}
}
+ @Override
+ public void cleanUp() {
+ removeJdkLoggingBridgeHandler();
+ }
+
+ private void configureJdkLoggingBridgeHandler() {
+ try {
+ if (bridgeHandlerIsAvailable()) {
+ removeJdkLoggingBridgeHandler();
+ SLF4JBridgeHandler.install();
+ }
+ }
+ catch (Throwable ex) {
+ // Ignore. No java.util.logging bridge is installed.
+ }
+ }
+
+ private boolean bridgeHandlerIsAvailable() {
+ return ClassUtils.isPresent("org.slf4j.bridge.SLF4JBridgeHandler",
+ getClassLoader());
+ }
+
+ private void removeJdkLoggingBridgeHandler() {
+ try {
+ if (bridgeHandlerIsAvailable()) {
+ try {
+ SLF4JBridgeHandler.removeHandlersForRootLogger();
+ }
+ catch (NoSuchMethodError ex) {
+ // Method missing in older versions of SLF4J like in JBoss AS 7.1
+ SLF4JBridgeHandler.uninstall();
+ }
+ }
+ }
+ catch (Throwable ex) {
+ // Ignore and continue
+ }
+ }
+
@Override
public void setLogLevel(String loggerName, LogLevel level) {
Logger logger = (StringUtils.hasLength(loggerName) ? LogManager
diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java
index d6338397eaf..fce8b0e7dbc 100644
--- a/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java
+++ b/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2014 the original author or authors.
+ * Copyright 2012-2015 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.
@@ -41,7 +41,7 @@ import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.util.ContextInitializer;
/**
- * {@link LoggingSystem} for for logback.
+ * {@link LoggingSystem} for logback.
*
* @author Phillip Webb
* @author Dave Syer
@@ -74,17 +74,15 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem {
configureJBossLoggingToUseSlf4j();
}
+ @Override
+ public void cleanUp() {
+ removeJdkLoggingBridgeHandler();
+ }
+
private void configureJdkLoggingBridgeHandler() {
try {
- if (ClassUtils.isPresent("org.slf4j.bridge.SLF4JBridgeHandler",
- getClassLoader())) {
- try {
- SLF4JBridgeHandler.removeHandlersForRootLogger();
- }
- catch (NoSuchMethodError ex) {
- // Method missing in older versions of SLF4J like in JBoss AS 7.1
- SLF4JBridgeHandler.uninstall();
- }
+ if (bridgeHandlerIsAvailable()) {
+ removeJdkLoggingBridgeHandler();
SLF4JBridgeHandler.install();
}
}
@@ -93,10 +91,32 @@ public class LogbackLoggingSystem extends AbstractLoggingSystem {
}
}
+ private boolean bridgeHandlerIsAvailable() {
+ return ClassUtils.isPresent("org.slf4j.bridge.SLF4JBridgeHandler",
+ getClassLoader());
+ }
+
private void configureJBossLoggingToUseSlf4j() {
System.setProperty("org.jboss.logging.provider", "slf4j");
}
+ private void removeJdkLoggingBridgeHandler() {
+ try {
+ if (bridgeHandlerIsAvailable()) {
+ try {
+ SLF4JBridgeHandler.removeHandlersForRootLogger();
+ }
+ catch (NoSuchMethodError ex) {
+ // Method missing in older versions of SLF4J like in JBoss AS 7.1
+ SLF4JBridgeHandler.uninstall();
+ }
+ }
+ }
+ catch (Throwable ex) {
+ // Ignore and continue
+ }
+ }
+
@Override
public void initialize(String configLocation) {
Assert.notNull(configLocation, "ConfigLocation must not be null");
diff --git a/spring-boot/src/test/java/org/springframework/boot/logging/LoggingApplicationListenerTests.java b/spring-boot/src/test/java/org/springframework/boot/logging/LoggingApplicationListenerTests.java
index eb871fa1dce..5ce26cac60a 100644
--- a/spring-boot/src/test/java/org/springframework/boot/logging/LoggingApplicationListenerTests.java
+++ b/spring-boot/src/test/java/org/springframework/boot/logging/LoggingApplicationListenerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2014 the original author or authors.
+ * Copyright 2012-2015 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.
@@ -18,7 +18,9 @@ package org.springframework.boot.logging;
import java.io.File;
import java.io.IOException;
+import java.util.logging.Handler;
import java.util.logging.LogManager;
+import java.util.logging.Logger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -28,11 +30,13 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.slf4j.bridge.SLF4JBridgeHandler;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.boot.logging.java.JavaLoggingSystem;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.boot.test.OutputCapture;
+import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.support.GenericApplicationContext;
import static org.hamcrest.Matchers.containsString;
@@ -46,6 +50,7 @@ import static org.junit.Assert.assertTrue;
*
* @author Dave Syer
* @author Phillip Webb
+ * @author Andy Wilkinson
*/
public class LoggingApplicationListenerTests {
@@ -261,4 +266,22 @@ public class LoggingApplicationListenerTests {
this.logger.debug("testatdebug");
assertThat(this.outputCapture.toString(), not(containsString("testatdebug")));
}
+
+ @Test
+ public void bridgeHandlerLifecycle() throws Exception {
+ assertTrue(bridgeHandlerInstalled());
+ this.initializer.onApplicationEvent(new ContextClosedEvent(this.context));
+ assertFalse(bridgeHandlerInstalled());
+ }
+
+ private boolean bridgeHandlerInstalled() {
+ Logger rootLogger = LogManager.getLogManager().getLogger("");
+ Handler[] handlers = rootLogger.getHandlers();
+ for (Handler handler : handlers) {
+ if (handler instanceof SLF4JBridgeHandler) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/spring-boot/src/test/java/org/springframework/boot/logging/log4j/Log4JLoggingSystemTests.java b/spring-boot/src/test/java/org/springframework/boot/logging/log4j/Log4JLoggingSystemTests.java
index 8fdc52b1a12..e4305511f6a 100644
--- a/spring-boot/src/test/java/org/springframework/boot/logging/log4j/Log4JLoggingSystemTests.java
+++ b/spring-boot/src/test/java/org/springframework/boot/logging/log4j/Log4JLoggingSystemTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2014 the original author or authors.
+ * Copyright 2012-2015 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.
@@ -16,16 +16,21 @@
package org.springframework.boot.logging.log4j;
+import java.util.logging.Handler;
+import java.util.logging.LogManager;
+
import org.apache.commons.logging.impl.Log4JLogger;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.slf4j.bridge.SLF4JBridgeHandler;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.test.OutputCapture;
import org.springframework.util.StringUtils;
import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -33,6 +38,7 @@ import static org.junit.Assert.assertTrue;
* Tests for {@link Log4JLoggingSystem}.
*
* @author Phillip Webb
+ * @author Andy Wilkinson
*/
public class Log4JLoggingSystemTests {
@@ -51,6 +57,7 @@ public class Log4JLoggingSystemTests {
@After
public void clear() {
+ this.loggingSystem.cleanUp();
System.clearProperty("LOG_FILE");
System.clearProperty("LOG_PATH");
System.clearProperty("PID");
@@ -89,4 +96,24 @@ public class Log4JLoggingSystemTests {
equalTo(1));
}
+ @Test
+ public void bridgeHandlerLifecycle() {
+ assertFalse(bridgeHandlerInstalled());
+ this.loggingSystem.beforeInitialize();
+ assertTrue(bridgeHandlerInstalled());
+ this.loggingSystem.cleanUp();
+ assertFalse(bridgeHandlerInstalled());
+ }
+
+ private boolean bridgeHandlerInstalled() {
+ java.util.logging.Logger rootLogger = LogManager.getLogManager().getLogger("");
+ Handler[] handlers = rootLogger.getHandlers();
+ for (Handler handler : handlers) {
+ if (handler instanceof SLF4JBridgeHandler) {
+ return true;
+ }
+ }
+ return false;
+ }
+
}
diff --git a/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java b/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java
index 331dacf9855..314db8c7daf 100644
--- a/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java
+++ b/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2014 the original author or authors.
+ * Copyright 2012-2015 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.
@@ -17,6 +17,8 @@
package org.springframework.boot.logging.logback;
import java.io.File;
+import java.util.logging.Handler;
+import java.util.logging.LogManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.impl.SLF4JLogFactory;
@@ -25,6 +27,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.ILoggerFactory;
+import org.slf4j.bridge.SLF4JBridgeHandler;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.test.OutputCapture;
@@ -72,6 +75,7 @@ public class LogbackLoggingSystemTests {
@After
public void clear() {
+ this.loggingSystem.cleanUp();
System.clearProperty("LOG_FILE");
System.clearProperty("LOG_PATH");
System.clearProperty("PID");
@@ -127,4 +131,24 @@ public class LogbackLoggingSystemTests {
assertEquals("slf4j", System.getProperty("org.jboss.logging.provider"));
}
+ @Test
+ public void bridgeHandlerLifecycle() {
+ assertFalse(bridgeHandlerInstalled());
+ this.loggingSystem.beforeInitialize();
+ assertTrue(bridgeHandlerInstalled());
+ this.loggingSystem.cleanUp();
+ assertFalse(bridgeHandlerInstalled());
+ }
+
+ private boolean bridgeHandlerInstalled() {
+ java.util.logging.Logger rootLogger = LogManager.getLogManager().getLogger("");
+ Handler[] handlers = rootLogger.getHandlers();
+ for (Handler handler : handlers) {
+ if (handler instanceof SLF4JBridgeHandler) {
+ return true;
+ }
+ }
+ return false;
+ }
+
}