Browse Source
During a restart, the Restarter runs all registered shutdown hooks. This breaks Log4J2 as it leaves it in a shutdown state that leaves logging switched off such that no output it produced when the application starts up again. This commit introduces a new RestartListener abstraction. RestartListeners are notified prior to the application being restarted. A Log4J2-specific implementation is provided that prepares Log4J2 for restart by removing any shutdown callbacks from its shutdown callback registry. This prevents the restart from shutting down Log4J2, ensuring that it still functions when the application restarts. Closes gh-4279pull/3160/merge
7 changed files with 145 additions and 10 deletions
@ -0,0 +1,62 @@
@@ -0,0 +1,62 @@
|
||||
/* |
||||
* 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. |
||||
* 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.devtools.log4j2; |
||||
|
||||
import java.lang.reflect.Field; |
||||
import java.util.Collection; |
||||
|
||||
import org.apache.logging.log4j.LogManager; |
||||
import org.apache.logging.log4j.core.util.Cancellable; |
||||
import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry; |
||||
import org.apache.logging.log4j.spi.LoggerContextFactory; |
||||
|
||||
import org.springframework.boot.devtools.restart.RestartListener; |
||||
import org.springframework.util.ClassUtils; |
||||
import org.springframework.util.ReflectionUtils; |
||||
|
||||
/** |
||||
* {@link RestartListener} that prepares Log4J2 for an application restart. |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
public class Log4J2RestartListener implements RestartListener { |
||||
|
||||
@Override |
||||
public void beforeRestart() { |
||||
if (ClassUtils.isPresent("org.apache.logging.log4j.LogManager", |
||||
getClass().getClassLoader())) { |
||||
prepareLog4J2ForRestart(); |
||||
} |
||||
} |
||||
|
||||
private void prepareLog4J2ForRestart() { |
||||
LoggerContextFactory factory = LogManager.getFactory(); |
||||
Field field = ReflectionUtils.findField(factory.getClass(), |
||||
"shutdownCallbackRegistry"); |
||||
ReflectionUtils.makeAccessible(field); |
||||
ShutdownCallbackRegistry shutdownCallbackRegistry = (ShutdownCallbackRegistry) ReflectionUtils |
||||
.getField(field, factory); |
||||
Field hooksField = ReflectionUtils.findField(shutdownCallbackRegistry.getClass(), |
||||
"hooks"); |
||||
ReflectionUtils.makeAccessible(hooksField); |
||||
@SuppressWarnings("unchecked") |
||||
Collection<Cancellable> state = (Collection<Cancellable>) ReflectionUtils |
||||
.getField(hooksField, shutdownCallbackRegistry); |
||||
state.clear(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
/* |
||||
* 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. |
||||
* 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.devtools.restart; |
||||
|
||||
/** |
||||
* Listener that is notified of application restarts. |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
public interface RestartListener { |
||||
|
||||
/** |
||||
* Called before an application restart. |
||||
*/ |
||||
void beforeRestart(); |
||||
|
||||
} |
||||
Loading…
Reference in new issue