Migrate Logging and Liquibase initializers to be listeners

This commit is contained in:
Dave Syer 2014-01-07 15:52:25 +00:00
parent 27ae6a5fd6
commit 3dacf4be17
13 changed files with 175 additions and 66 deletions

View File

@ -23,7 +23,7 @@ import org.springframework.boot.autoconfigure.AutoConfigurationReportLoggingInit
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.context.initializer.LoggingApplicationContextInitializer;
import org.springframework.boot.context.listener.LoggingApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
@ -170,7 +170,7 @@ public class ManagementSecurityAutoConfigurationTests {
private static AnnotationConfigWebApplicationContext debugRefresh(
AnnotationConfigWebApplicationContext context) {
TestUtils.addEnviroment(context, "debug:true");
LoggingApplicationContextInitializer logging = new LoggingApplicationContextInitializer();
LoggingApplicationListener logging = new LoggingApplicationListener();
logging.initialize(context);
AutoConfigurationReportLoggingInitializer initializer = new AutoConfigurationReportLoggingInitializer();
initializer.initialize(context);

View File

@ -23,7 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.web.DefaultErrorViewIntegrationTests.TestConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.initializer.LoggingApplicationContextInitializer;
import org.springframework.boot.context.listener.LoggingApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
@ -41,7 +41,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
/**
* @author Dave Syer
*/
@ContextConfiguration(classes = TestConfiguration.class, initializers = { LoggingApplicationContextInitializer.class })
@ContextConfiguration(classes = TestConfiguration.class, initializers = { LoggingApplicationListener.class })
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
public class DefaultErrorViewIntegrationTests {

View File

@ -24,7 +24,7 @@ import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfigurati
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.test.City;
import org.springframework.boot.context.initializer.LoggingApplicationContextInitializer;
import org.springframework.boot.context.listener.LoggingApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ -117,7 +117,7 @@ public class SecurityAutoConfigurationTests {
private static AnnotationConfigWebApplicationContext debugRefresh(
AnnotationConfigWebApplicationContext context) {
TestUtils.addEnviroment(context, "debug:true");
LoggingApplicationContextInitializer logging = new LoggingApplicationContextInitializer();
LoggingApplicationListener logging = new LoggingApplicationListener();
logging.initialize(context);
AutoConfigurationReportLoggingInitializer initializer = new AutoConfigurationReportLoggingInitializer();
initializer.initialize(context);

View File

@ -320,17 +320,19 @@ public class SpringApplication {
}
// Notify listeners of the environment creation
multicaster.multicastEvent(new SpringApplicationNewEnvironmentEvent(this,
environment, args));
multicaster.multicastEvent(new SpringApplicationEnvironmentAvailableEvent(
this, environment, args));
// Sources might have changed when environment was applied
sources = getSources();
registerListeners(multicaster, sources);
Assert.notEmpty(sources, "Sources must not be empty");
if (this.showBanner) {
printBanner();
}
// Some sources might be listeners
registerListeners(multicaster, sources);
// Create, load, refresh and run the ApplicationContext
context = createApplicationContext();
registerApplicationEventMulticaster(context, multicaster);
@ -343,6 +345,9 @@ public class SpringApplication {
}
load(context, sources.toArray(new Object[sources.size()]));
// Notify listeners of intention to refresh
multicaster.multicastEvent(new SpringApplicationBeforeRefreshEvent(this,
context, args));
refresh(context);
stopWatch.stop();

View File

@ -0,0 +1,69 @@
/*
* Copyright 2012-2013 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;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
/**
* Event published as when a {@link SpringApplication} is starting up and the
* {@link ApplicationContext} is about to refresh. The bean definitions will be loaded and
* the {@link Environment} is ready for use at this stage.
*
* @author Dave Syer
*/
public class SpringApplicationBeforeRefreshEvent extends ApplicationEvent {
private String[] args;
private ConfigurableApplicationContext context;
/**
* @param springApplication the current application
* @param context the ApplicationContext about to be refreshed
* @param args the argumemts the application is running with
*/
public SpringApplicationBeforeRefreshEvent(SpringApplication springApplication,
ConfigurableApplicationContext context, String[] args) {
super(springApplication);
this.context = context;
this.args = args;
}
/**
* @return the springApplication
*/
public SpringApplication getSpringApplication() {
return (SpringApplication) getSource();
}
/**
* @return the args
*/
public String[] getArgs() {
return this.args;
}
/**
* @return the context
*/
public ConfigurableApplicationContext getApplicationContext() {
return this.context;
}
}

View File

@ -21,12 +21,12 @@ import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
/**
* Event published as early when a {@link SpringApplication} is starting up and the
* Event published when a {@link SpringApplication} is starting up and the
* {@link Environment} is first available for inspection and modification.
*
* @author Dave Syer
*/
public class SpringApplicationNewEnvironmentEvent extends ApplicationEvent {
public class SpringApplicationEnvironmentAvailableEvent extends ApplicationEvent {
private ConfigurableEnvironment environment;
private String[] args;
@ -36,8 +36,9 @@ public class SpringApplicationNewEnvironmentEvent extends ApplicationEvent {
* @param environment the environment that was just created
* @param args the argumemts the application is running with
*/
public SpringApplicationNewEnvironmentEvent(SpringApplication springApplication,
ConfigurableEnvironment environment, String[] args) {
public SpringApplicationEnvironmentAvailableEvent(
SpringApplication springApplication, ConfigurableEnvironment environment,
String[] args) {
super(springApplication);
this.environment = environment;
this.args = args;

View File

@ -30,7 +30,7 @@ import java.util.Set;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationNewEnvironmentEvent;
import org.springframework.boot.SpringApplicationEnvironmentAvailableEvent;
import org.springframework.boot.bind.PropertySourcesPropertyValues;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.config.PropertiesPropertySourceLoader;
@ -89,7 +89,7 @@ import org.springframework.util.StringUtils;
*/
public class ConfigFileApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext>,
ApplicationListener<SpringApplicationNewEnvironmentEvent>, Ordered {
ApplicationListener<SpringApplicationEnvironmentAvailableEvent>, Ordered {
private static final String LOCATION_VARIABLE = "${spring.config.location}";
@ -114,7 +114,7 @@ public class ConfigFileApplicationContextInitializer implements
* ("spring.main.show_banner=false").
*/
@Override
public void onApplicationEvent(SpringApplicationNewEnvironmentEvent event) {
public void onApplicationEvent(SpringApplicationEnvironmentAvailableEvent event) {
Environment created = event.getEnvironment();
if (created instanceof ConfigurableEnvironment) {
SpringApplication springApplication = event.getSpringApplication();

View File

@ -14,24 +14,29 @@
* limitations under the License.
*/
package org.springframework.boot.context.initializer;
package org.springframework.boot.context.listener;
import java.lang.management.ManagementFactory;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationBeforeRefreshEvent;
import org.springframework.boot.SpringApplicationEnvironmentAvailableEvent;
import org.springframework.boot.SpringApplicationStartEvent;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.util.ClassUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ResourceUtils;
@ -50,7 +55,7 @@ import org.springframework.util.ResourceUtils;
* logback; and <code>classpath:logging.properties</code> for
* <code>java.util.logging</code>. If the correct one of those files is not found then
* some sensible defaults are adopted from files of the same name but in the package
* containing {@link LoggingApplicationContextInitializer}.
* containing {@link LoggingApplicationListener}.
* </p>
*
* <p>
@ -68,9 +73,7 @@ import org.springframework.util.ResourceUtils;
* @author Dave Syer
* @author Phillip Webb
*/
public class LoggingApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext>,
ApplicationListener<SpringApplicationStartEvent>, Ordered {
public class LoggingApplicationListener implements SmartApplicationListener {
private static final Map<String, String> ENVIRONMENT_SYSTEM_PROPERTY_MAPPING;
static {
@ -90,6 +93,12 @@ public class LoggingApplicationContextInitializer implements
LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.hibernate.tool.hbm2ddl");
}
@SuppressWarnings("unchecked")
private static Collection<Class<? extends ApplicationEvent>> EVENT_TYPES = Arrays
.<Class<? extends ApplicationEvent>> asList(
SpringApplicationStartEvent.class,
SpringApplicationBeforeRefreshEvent.class);
private final Log logger = LogFactory.getLog(getClass());
private int order = Integer.MIN_VALUE + 11;
@ -99,23 +108,42 @@ public class LoggingApplicationContextInitializer implements
private LogLevel springBootLogging = null;
@Override
public void onApplicationEvent(SpringApplicationStartEvent event) {
if (System.getProperty("PID") == null) {
System.setProperty("PID", getPid());
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
for (Class<? extends ApplicationEvent> type : EVENT_TYPES) {
if (type.isAssignableFrom(eventType)) {
return true;
}
}
return false;
}
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return SpringApplication.class.isAssignableFrom(sourceType);
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof SpringApplicationEnvironmentAvailableEvent) {
SpringApplicationEnvironmentAvailableEvent available = (SpringApplicationEnvironmentAvailableEvent) event;
initialize(available.getEnvironment(), available.getSpringApplication()
.getClassLoader());
}
else {
if (System.getProperty("PID") == null) {
System.setProperty("PID", getPid());
}
LoggingSystem loggingSystem = LoggingSystem.get(ClassUtils
.getDefaultClassLoader());
loggingSystem.beforeInitialize();
}
LoggingSystem loggingSystem = LoggingSystem.get(event.getSpringApplication()
.getClass().getClassLoader());
loggingSystem.beforeInitialize();
}
/**
* Initialize the logging system according to preferences expressed through the
* {@link Environment} and the classpath.
*/
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
protected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) {
if (this.parseArgs && this.springBootLogging == null) {
if (environment.containsProperty("debug")) {
@ -134,7 +162,7 @@ public class LoggingApplicationContextInitializer implements
}
}
LoggingSystem system = LoggingSystem.get(applicationContext.getClassLoader());
LoggingSystem system = LoggingSystem.get(classLoader);
// User specified configuration
if (environment.containsProperty("logging.config")) {

View File

@ -6,9 +6,7 @@ import liquibase.servicelocator.ServiceLocator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.SpringApplicationStartEvent;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.ClassUtils;
/**
@ -19,7 +17,6 @@ import org.springframework.util.ClassUtils;
* @author Dave Syer
*/
public class LiquibaseServiceLocatorInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext>,
ApplicationListener<SpringApplicationStartEvent> {
static final Log logger = LogFactory.getLog(LiquibaseServiceLocatorInitializer.class);
@ -31,10 +28,6 @@ public class LiquibaseServiceLocatorInitializer implements
}
}
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
}
/**
* Inner class to prevent class not found issues
*/

View File

@ -4,6 +4,9 @@ org.springframework.boot.context.initializer.ConfigFileApplicationContextInitial
org.springframework.boot.context.initializer.FileEncodingApplicationContextInitializer,\
org.springframework.boot.context.initializer.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.initializer.EnvironmentDelegateApplicationContextInitializer,\
org.springframework.boot.context.initializer.LoggingApplicationContextInitializer,\
org.springframework.boot.context.initializer.VcapApplicationContextInitializer,\
org.springframework.boot.context.initializer.VcapApplicationContextInitializer
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.context.listener.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorInitializer

View File

@ -176,7 +176,7 @@ public class SpringApplicationBuilderTests {
SpringApplicationBuilder application = new SpringApplicationBuilder(
ExampleConfig.class).web(false);
this.context = application.run();
assertEquals(7, application.application().getInitializers().size());
assertEquals(5, application.application().getInitializers().size());
}
@Test
@ -184,7 +184,7 @@ public class SpringApplicationBuilderTests {
SpringApplicationBuilder application = new SpringApplicationBuilder(
ExampleConfig.class).child(ChildConfig.class).web(false);
this.context = application.run();
assertEquals(8, application.application().getInitializers().size());
assertEquals(6, application.application().getInitializers().size());
}
@Test
@ -198,7 +198,7 @@ public class SpringApplicationBuilderTests {
}
});
this.context = application.run();
assertEquals(8, application.application().getInitializers().size());
assertEquals(6, application.application().getInitializers().size());
}
@Configuration

View File

@ -22,7 +22,7 @@ import java.util.Map;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationNewEnvironmentEvent;
import org.springframework.boot.SpringApplicationEnvironmentAvailableEvent;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@ -67,7 +67,7 @@ public class ConfigFileApplicationContextInitializerTests {
@Test
public void randomValue() throws Exception {
StandardEnvironment environment = new StandardEnvironment();
this.initializer.onApplicationEvent(new SpringApplicationNewEnvironmentEvent(
this.initializer.onApplicationEvent(new SpringApplicationEnvironmentAvailableEvent(
new SpringApplication(), environment, new String[0]));
String property = environment.getProperty("random.value");
assertThat(property, notNullValue());

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.context.initializer;
package org.springframework.boot.context.listener;
import java.io.IOException;
import java.util.logging.LogManager;
@ -31,7 +31,6 @@ import org.springframework.boot.OutputCapture;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationStartEvent;
import org.springframework.boot.TestUtils;
import org.springframework.boot.context.initializer.LoggingApplicationContextInitializer;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.java.JavaLoggingSystem;
import org.springframework.context.support.GenericApplicationContext;
@ -43,12 +42,12 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
* Tests for {@link LoggingApplicationContextInitializer}.
* Tests for {@link LoggingApplicationListener}.
*
* @author Dave Syer
* @author Phillip Webb
*/
public class LoggingApplicationContextInitializerTests {
public class LoggingApplicationListenerTests {
private static final String[] NO_ARGS = {};
@ -58,7 +57,7 @@ public class LoggingApplicationContextInitializerTests {
@Rule
public OutputCapture outputCapture = new OutputCapture();
private LoggingApplicationContextInitializer initializer = new LoggingApplicationContextInitializer();
private LoggingApplicationListener initializer = new LoggingApplicationListener();
private Log logger = new SLF4JLogFactory().getInstance(getClass());
@ -79,12 +78,15 @@ public class LoggingApplicationContextInitializerTests {
System.clearProperty("LOG_FILE");
System.clearProperty("LOG_PATH");
System.clearProperty("PID");
if (this.context != null) {
this.context.close();
}
}
@Test
public void testDefaultConfigLocation() {
GenericApplicationContext context = new GenericApplicationContext();
this.initializer.initialize(context);
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
this.logger.info("Hello world");
String output = this.outputCapture.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
@ -95,7 +97,8 @@ public class LoggingApplicationContextInitializerTests {
public void testOverrideConfigLocation() {
TestUtils.addEnviroment(this.context,
"logging.config: classpath:logback-nondefault.xml");
this.initializer.initialize(this.context);
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
this.logger.info("Hello world");
String output = this.outputCapture.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
@ -106,7 +109,8 @@ public class LoggingApplicationContextInitializerTests {
@Test
public void testOverrideConfigDoesNotExist() throws Exception {
TestUtils.addEnviroment(this.context, "logging.config: doesnotexist.xml");
this.initializer.initialize(this.context);
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
// Should not throw
}
@ -115,8 +119,9 @@ public class LoggingApplicationContextInitializerTests {
TestUtils.addEnviroment(this.context,
"logging.config: classpath:logback-nondefault.xml",
"logging.file: foo.log");
this.initializer.initialize(this.context);
Log logger = LogFactory.getLog(LoggingApplicationContextInitializerTests.class);
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class);
logger.info("Hello world");
String output = this.outputCapture.toString().trim();
assertTrue("Wrong output:\n" + output, output.startsWith("foo.log"));
@ -126,8 +131,9 @@ public class LoggingApplicationContextInitializerTests {
public void testAddLogPathProperty() {
TestUtils.addEnviroment(this.context,
"logging.config: classpath:logback-nondefault.xml", "logging.path: foo/");
this.initializer.initialize(this.context);
Log logger = LogFactory.getLog(LoggingApplicationContextInitializerTests.class);
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class);
logger.info("Hello world");
String output = this.outputCapture.toString().trim();
assertTrue("Wrong output:\n" + output, output.startsWith("foo/spring.log"));
@ -136,7 +142,8 @@ public class LoggingApplicationContextInitializerTests {
@Test
public void parseDebugArg() throws Exception {
TestUtils.addEnviroment(this.context, "debug");
this.initializer.initialize(this.context);
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
this.logger.debug("testatdebug");
this.logger.trace("testattrace");
assertThat(this.outputCapture.toString(), containsString("testatdebug"));
@ -146,7 +153,8 @@ public class LoggingApplicationContextInitializerTests {
@Test
public void parseTraceArg() throws Exception {
TestUtils.addEnviroment(this.context, "trace");
this.initializer.initialize(this.context);
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
this.logger.debug("testatdebug");
this.logger.trace("testattrace");
assertThat(this.outputCapture.toString(), containsString("testatdebug"));
@ -157,7 +165,8 @@ public class LoggingApplicationContextInitializerTests {
public void parseArgsDisabled() throws Exception {
this.initializer.setParseArgs(false);
TestUtils.addEnviroment(this.context, "debug");
this.initializer.initialize(this.context);
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
this.logger.debug("testatdebug");
assertThat(this.outputCapture.toString(), not(containsString("testatdebug")));
}
@ -168,7 +177,8 @@ public class LoggingApplicationContextInitializerTests {
this.initializer.setParseArgs(false);
this.initializer.onApplicationEvent(new SpringApplicationStartEvent(
this.springApplication, new String[] { "--debug" }));
this.initializer.initialize(this.context);
this.initializer.initialize(this.context.getEnvironment(),
this.context.getClassLoader());
this.logger.debug("testatdebug");
assertThat(this.outputCapture.toString(), not(containsString("testatdebug")));
}