Perform background preinitialization after logging system setup

Previously, BackgroundPreinitializer would kick off preinitialization
on a separate thread in response to an ApplicationStartedEvent. This
work would then race with the logging system being set up in response
to an ApplicationEnvironmentPreparedEvent. When Logback’s being used
this race is problematic. As part of Logback’s setup,
LoggerContext.stop() is called. This calls LoggerContext.reset() which
can fail with a ConcurrentModificationException if another thread tries
to create a Logger at the same time. This is a known bug in Logback [1].

This commit updates BackgroundPreinitializer to respond to
an ApplicationEnvironmentPreparedEvent and to order itself so that it’s
called after LoggingApplicationListener has responded to the same event
by initializing the logging system.

Closes gh-4871

[1] http://jira.qos.ch/browse/LOGBACK-397
This commit is contained in:
Andy Wilkinson 2016-01-20 11:46:46 +00:00
parent 00f4538529
commit b85b60828c
1 changed files with 8 additions and 4 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2015 the original author or authors. * Copyright 2012-2016 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.
@ -23,8 +23,10 @@ import javax.validation.Validation;
import org.apache.catalina.mbeans.MBeanFactory; import org.apache.catalina.mbeans.MBeanFactory;
import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.logging.LoggingApplicationListener;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.Order;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter; import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
/** /**
@ -32,13 +34,15 @@ import org.springframework.http.converter.support.AllEncompassingFormHttpMessage
* time consuming tasks. * time consuming tasks.
* *
* @author Phillip Webb * @author Phillip Webb
* @author Andy Wilkinson
* @since 1.3.0 * @since 1.3.0
*/ */
@Order(LoggingApplicationListener.DEFAULT_ORDER + 1)
public class BackgroundPreinitializer public class BackgroundPreinitializer
implements ApplicationListener<ApplicationStartedEvent> { implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
@Override @Override
public void onApplicationEvent(ApplicationStartedEvent event) { public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
try { try {
ExecutorService executor = Executors.newSingleThreadExecutor(); ExecutorService executor = Executors.newSingleThreadExecutor();
submit(executor, new MessageConverterInitializer()); submit(executor, new MessageConverterInitializer());