Make configuration of Liquibase’s logging more robust

We make Liquibase aware of our custom Commons Logging-based logger by
adding its package to the Liquibase ServiceLocator’s packages to scan.
Previously, this was happening too late so Liquibase may have already
initialized and cached a particular logger.

This commit moves the registration of the extra package from the
Liquibase auto-configuration to the application listener that customises
Liquibase’s ServiceLocator. This ensures that the package is added
before Liquibase is used. Unfortunately, configuring Liquibase’s
ServiceLocator and its packages to scan causes it to try to perform
some logging, resulting in it caching the wrong type of logger. We
work around this problem by resetting Liquibase’s LogFactory once we’ve
finished setting everything up.

Closes gh-6713
This commit is contained in:
Andy Wilkinson 2016-08-22 14:58:34 +01:00
parent 9300c6d422
commit ba51dc5c4a
3 changed files with 21 additions and 11 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");
* you may not use this file except in compliance with the License.
@ -21,7 +21,6 @@ import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import liquibase.integration.spring.SpringLiquibase;
import liquibase.servicelocator.ServiceLocator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
@ -35,7 +34,6 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.liquibase.CommonsLoggingLiquibaseLogger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@ -52,6 +50,7 @@ import org.springframework.util.Assert;
* @author Marcel Overdijk
* @author Dave Syer
* @author Phillip Webb
* @author Andy Wilkinson
* @since 1.1.0
*/
@Configuration
@ -87,9 +86,6 @@ public class LiquibaseAutoConfiguration {
+ " (please add changelog or check your Liquibase "
+ "configuration)");
}
ServiceLocator serviceLocator = ServiceLocator.getInstance();
serviceLocator.addPackageToScan(
CommonsLoggingLiquibaseLogger.class.getPackage().getName());
}
@Bean

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");
* you may not use this file except in compliance with the License.
@ -29,33 +29,42 @@ import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
import org.springframework.boot.liquibase.CommonsLoggingLiquibaseLogger;
import org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.boot.test.OutputCapture;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.util.ReflectionTestUtils;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.contains;
/**
* Tests for {@link LiquibaseAutoConfiguration}.
*
* @author Marcel Overdijk
* @author Andy Wilkinson
*/
public class LiquibaseAutoConfigurationTests {
@Rule
public ExpectedException expected = ExpectedException.none();
@Rule
public OutputCapture outputCapture = new OutputCapture();
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@Before
public void init() {
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.name:liquibasetest");
new LiquibaseServiceLocatorApplicationListener().onApplicationEvent(null);
}
@After
@ -166,7 +175,8 @@ public class LiquibaseAutoConfigurationTests {
this.context.refresh();
SpringLiquibase liquibase = this.context.getBean(SpringLiquibase.class);
Object log = ReflectionTestUtils.getField(liquibase, "log");
assertThat(log, instanceOf(CommonsLoggingLiquibaseLogger.class));
assertThat(log, instanceOf((CommonsLoggingLiquibaseLogger.class)));
assertThat(this.outputCapture.toString(), not(contains(": liquibase:")));
}
@Test

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2016 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.
@ -51,8 +51,12 @@ public class LiquibaseServiceLocatorApplicationListener
private static class LiquibasePresent {
public void replaceServiceLocator() {
ServiceLocator.setInstance(new CustomResolverServiceLocator(
new SpringPackageScanClassResolver(logger)));
CustomResolverServiceLocator customResolverServiceLocator = new CustomResolverServiceLocator(
new SpringPackageScanClassResolver(logger));
customResolverServiceLocator.addPackageToScan(
CommonsLoggingLiquibaseLogger.class.getPackage().getName());
ServiceLocator.setInstance(customResolverServiceLocator);
liquibase.logging.LogFactory.reset();
}
}