mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Fix package tangle
Fix package tangle between the `org.springframework.boot` and the `event` sub-package. A new `SpringApplicationRunParticipant` abstraction has been introduced, with the `event` package solely responsible for handling event multi-casting.
This commit is contained in:
parent
c0a5c763b6
commit
042e512d3d
@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.boot;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -31,28 +32,18 @@ import java.util.Set;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.boot.event.ApplicationEnvironmentPreparedEvent;
|
||||
import org.springframework.boot.event.ApplicationFailedEvent;
|
||||
import org.springframework.boot.event.ApplicationPreparedEvent;
|
||||
import org.springframework.boot.event.ApplicationStartedEvent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
|
||||
import org.springframework.context.event.ApplicationEventMulticaster;
|
||||
import org.springframework.context.event.SimpleApplicationEventMulticaster;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
@ -72,6 +63,7 @@ import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StopWatch;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
@ -243,36 +235,6 @@ public class SpringApplication {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns objects loaded via the {@link SpringFactoriesLoader}.
|
||||
*/
|
||||
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
|
||||
ClassLoader classLoader = SpringApplication.class.getClassLoader();
|
||||
|
||||
// Use names and ensure unique to protect against duplicates
|
||||
Set<String> names = new LinkedHashSet<String>(
|
||||
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
|
||||
List<T> instances = new ArrayList<T>(names.size());
|
||||
|
||||
// Create instances from the names
|
||||
for (String name : names) {
|
||||
try {
|
||||
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
|
||||
Assert.isAssignable(type, instanceClass);
|
||||
@SuppressWarnings("unchecked")
|
||||
T instance = (T) instanceClass.newInstance();
|
||||
instances.add(instance);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalArgumentException("Cannot instantiate " + type + " : "
|
||||
+ name, ex);
|
||||
}
|
||||
}
|
||||
|
||||
AnnotationAwareOrderComparator.sort(instances);
|
||||
return instances;
|
||||
}
|
||||
|
||||
private Class<?> deduceMainApplicationClass() {
|
||||
try {
|
||||
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
|
||||
@ -302,23 +264,19 @@ public class SpringApplication {
|
||||
|
||||
System.setProperty("java.awt.headless", Boolean.toString(this.headless));
|
||||
|
||||
ApplicationEventMulticaster multicaster = createApplicationEventMulticaster();
|
||||
try {
|
||||
// Allow logging and stuff to initialize very early
|
||||
multicaster.multicastEvent(new ApplicationStartedEvent(this, args));
|
||||
Collection<SpringApplicationRunParticipant> participants = createRunParticipants(args);
|
||||
for (SpringApplicationRunParticipant participant : participants) {
|
||||
participant.started();
|
||||
}
|
||||
|
||||
try {
|
||||
// Create and configure the environment
|
||||
ConfigurableEnvironment environment = getOrCreateEnvironment();
|
||||
addPropertySources(environment, args);
|
||||
setupProfiles(environment);
|
||||
|
||||
// Notify listeners of the environment creation
|
||||
multicaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this,
|
||||
args, environment));
|
||||
|
||||
// Load the sources (might have changed when environment was applied)
|
||||
Set<Object> sources = getSources();
|
||||
Assert.notEmpty(sources, "Sources must not be empty");
|
||||
for (SpringApplicationRunParticipant participant : participants) {
|
||||
participant.environmentPrepared(environment);
|
||||
}
|
||||
|
||||
if (this.showBanner) {
|
||||
printBanner();
|
||||
@ -326,48 +284,93 @@ public class SpringApplication {
|
||||
|
||||
// Create, load, refresh and run the ApplicationContext
|
||||
context = createApplicationContext();
|
||||
registerApplicationEventMulticaster(context, multicaster);
|
||||
context.registerShutdownHook();
|
||||
context.setEnvironment(environment);
|
||||
postProcessApplicationContext(context);
|
||||
applyInitializers(context);
|
||||
for (SpringApplicationRunParticipant participant : participants) {
|
||||
participant.contextPrepared(context);
|
||||
}
|
||||
if (this.logStartupInfo) {
|
||||
logStartupInfo(context.getParent() == null);
|
||||
}
|
||||
|
||||
// Load the sources
|
||||
Set<Object> sources = getSources();
|
||||
Assert.notEmpty(sources, "Sources must not be empty");
|
||||
load(context, sources.toArray(new Object[sources.size()]));
|
||||
for (SpringApplicationRunParticipant participant : participants) {
|
||||
participant.contextLoaded(context);
|
||||
}
|
||||
|
||||
// Notify listeners of intention to refresh
|
||||
multicaster.multicastEvent(new ApplicationPreparedEvent(this, args, context));
|
||||
|
||||
// Refresh the context
|
||||
refresh(context);
|
||||
afterRefresh(context, args);
|
||||
for (SpringApplicationRunParticipant participant : participants) {
|
||||
participant.finished(context, null);
|
||||
}
|
||||
|
||||
stopWatch.stop();
|
||||
if (this.logStartupInfo) {
|
||||
new StartupInfoLogger(this.mainApplicationClass).logStarted(
|
||||
getApplicationLog(), stopWatch);
|
||||
}
|
||||
|
||||
afterRefresh(context, args);
|
||||
return context;
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
handleFailure(context, multicaster, ex, args);
|
||||
throw ex;
|
||||
catch (Exception ex) {
|
||||
for (SpringApplicationRunParticipant participant : participants) {
|
||||
finishWithException(participant, context, ex);
|
||||
}
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
ReflectionUtils.rethrowRuntimeException(ex);
|
||||
return context;
|
||||
}
|
||||
catch (Error ex) {
|
||||
handleFailure(context, multicaster, ex, args);
|
||||
throw ex;
|
||||
finally {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ApplicationEventMulticaster createApplicationEventMulticaster() {
|
||||
ApplicationEventMulticaster multicaster = new SpringApplicationEventMulticaster();
|
||||
for (ApplicationListener<?> listener : getListeners()) {
|
||||
multicaster.addApplicationListener(listener);
|
||||
private Collection<SpringApplicationRunParticipant> createRunParticipants(
|
||||
String[] args) {
|
||||
List<SpringApplicationRunParticipant> participants = new ArrayList<SpringApplicationRunParticipant>();
|
||||
participants.addAll(getSpringFactoriesInstances(
|
||||
SpringApplicationRunParticipant.class, new Class<?>[] {
|
||||
SpringApplication.class, String[].class }, this, args));
|
||||
return participants;
|
||||
}
|
||||
|
||||
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
|
||||
return getSpringFactoriesInstances(type, new Class<?>[] {});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
|
||||
Class<?>[] parameterTypes, Object... args) {
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
|
||||
// Use names and ensure unique to protect against duplicates
|
||||
Set<String> names = new LinkedHashSet<String>(
|
||||
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
|
||||
List<T> instances = new ArrayList<T>(names.size());
|
||||
|
||||
// Create instances from the names
|
||||
for (String name : names) {
|
||||
try {
|
||||
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
|
||||
Assert.isAssignable(type, instanceClass);
|
||||
Constructor<?> constructor = instanceClass.getConstructor(parameterTypes);
|
||||
T instance = (T) constructor.newInstance(args);
|
||||
instances.add(instance);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalArgumentException("Cannot instantiate " + type + " : "
|
||||
+ name, ex);
|
||||
}
|
||||
}
|
||||
return multicaster;
|
||||
|
||||
AnnotationAwareOrderComparator.sort(instances);
|
||||
return instances;
|
||||
}
|
||||
|
||||
private ConfigurableEnvironment getOrCreateEnvironment() {
|
||||
@ -450,17 +453,6 @@ public class SpringApplication {
|
||||
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
|
||||
}
|
||||
|
||||
private void registerApplicationEventMulticaster(
|
||||
ConfigurableApplicationContext context,
|
||||
ApplicationEventMulticaster multicaster) {
|
||||
context.getBeanFactory().registerSingleton(
|
||||
AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
|
||||
multicaster);
|
||||
if (multicaster instanceof BeanFactoryAware) {
|
||||
((BeanFactoryAware) multicaster).setBeanFactory(context.getBeanFactory());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any relevant post processing the {@link ApplicationContext}. Subclasses can
|
||||
* apply additional processing as required.
|
||||
@ -624,29 +616,23 @@ public class SpringApplication {
|
||||
((AbstractApplicationContext) applicationContext).refresh();
|
||||
}
|
||||
|
||||
private void afterRefresh(ConfigurableApplicationContext context, String[] args) {
|
||||
protected void afterRefresh(ConfigurableApplicationContext context, String[] args) {
|
||||
runCommandLineRunners(context, args);
|
||||
}
|
||||
|
||||
protected void handleFailure(ConfigurableApplicationContext context,
|
||||
ApplicationEventMulticaster multicaster, Throwable exception, String... args) {
|
||||
private void finishWithException(SpringApplicationRunParticipant participant,
|
||||
ConfigurableApplicationContext context, Exception exception) {
|
||||
try {
|
||||
multicaster.multicastEvent(new ApplicationFailedEvent(this, args, context,
|
||||
exception));
|
||||
participant.finished(context, exception);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// We don't want to fail here and mask the original exception
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.error("Error handling failed", ex);
|
||||
}
|
||||
else {
|
||||
this.log.warn("Error handling failed (" + ex.getMessage() == null ? "no error message"
|
||||
: ex.getMessage() + ")");
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (context != null) {
|
||||
context.close();
|
||||
String message = ex.getMessage();
|
||||
message = (message == null ? "no error message" : message);
|
||||
this.log.warn("Error handling failed (" + message + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -974,38 +960,4 @@ public class SpringApplication {
|
||||
return new LinkedHashSet<E>(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ApplicationEventMulticaster} and {@link ApplicationEventPublisher} for
|
||||
* {@link SpringApplication} events.
|
||||
*/
|
||||
private static class SpringApplicationEventMulticaster extends
|
||||
SimpleApplicationEventMulticaster implements ApplicationEventPublisher {
|
||||
|
||||
@Override
|
||||
public void publishEvent(ApplicationEvent event) {
|
||||
multicastEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<ApplicationListener<?>> getApplicationListeners(
|
||||
ApplicationEvent event) {
|
||||
List<ApplicationListener<?>> listeners = new ArrayList<ApplicationListener<?>>();
|
||||
listeners.addAll(super.getApplicationListeners(event));
|
||||
if (event instanceof ApplicationFailedEvent) {
|
||||
Collections.reverse(listeners);
|
||||
}
|
||||
return listeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addApplicationListener(ApplicationListener<?> listener) {
|
||||
super.addApplicationListener(listener);
|
||||
if (listener instanceof ApplicationEventPublisherAware) {
|
||||
((ApplicationEventPublisherAware) listener)
|
||||
.setApplicationEventPublisher(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2012-2014 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.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
|
||||
/**
|
||||
* Strategy class to allow dynamic participation when the {@link SpringApplication}
|
||||
* {@code run} method is called. Participants are loaded via the
|
||||
* {@link SpringFactoriesLoader} and should declare a public constructor that accepts a
|
||||
* {@link SpringApplication} instance and a {@code String[]} of arguments. A new
|
||||
* {@link SpringApplicationRunParticipant} instance will be created for each run.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public interface SpringApplicationRunParticipant {
|
||||
|
||||
/**
|
||||
* Called immediately when the run method has first started. Can be used for very
|
||||
* early initialization.
|
||||
*/
|
||||
void started();
|
||||
|
||||
/**
|
||||
* Called once the environment has been prepared, but before the
|
||||
* {@link ApplicationContext} has been created.
|
||||
* @param environment the environment
|
||||
*/
|
||||
void environmentPrepared(ConfigurableEnvironment environment);
|
||||
|
||||
/**
|
||||
* Called once the {@link ApplicationContext} has been created and prepared, but
|
||||
* before sources have been loaded.
|
||||
* @param context the application context
|
||||
*/
|
||||
void contextPrepared(ConfigurableApplicationContext context);
|
||||
|
||||
/**
|
||||
* Called once the application context has been loaded but before it has been
|
||||
* refreshed.
|
||||
* @param context the application context
|
||||
*/
|
||||
void contextLoaded(ConfigurableApplicationContext context);
|
||||
|
||||
/**
|
||||
* Called immediately before the run method finishes.
|
||||
* @param context the application context
|
||||
* @param exception any run exception or null if run completed successfully.
|
||||
*/
|
||||
void finished(ConfigurableApplicationContext context, Throwable exception);
|
||||
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2012-2014 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.event;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringApplicationRunParticipant;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.event.ApplicationEventMulticaster;
|
||||
import org.springframework.context.event.SimpleApplicationEventMulticaster;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
/**
|
||||
* {@link SpringApplicationRunParticipant} to publish {@link SpringApplicationEvent}s.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class EventPublishingRunParticipant implements SpringApplicationRunParticipant {
|
||||
|
||||
private final ApplicationEventMulticaster multicaster;
|
||||
|
||||
private SpringApplication application;
|
||||
|
||||
private String[] args;
|
||||
|
||||
public EventPublishingRunParticipant(SpringApplication application, String[] args) {
|
||||
this.application = application;
|
||||
this.args = args;
|
||||
this.multicaster = new SimpleApplicationEventMulticaster();
|
||||
for (ApplicationListener<?> listener : application.getListeners()) {
|
||||
this.multicaster.addApplicationListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void started() {
|
||||
publishEvent(new ApplicationStartedEvent(this.application, this.args));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void environmentPrepared(ConfigurableEnvironment environment) {
|
||||
publishEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args,
|
||||
environment));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextPrepared(ConfigurableApplicationContext context) {
|
||||
registerApplicationEventMulticaster(context);
|
||||
}
|
||||
|
||||
private void registerApplicationEventMulticaster(
|
||||
ConfigurableApplicationContext context) {
|
||||
context.getBeanFactory().registerSingleton(
|
||||
AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
|
||||
this.multicaster);
|
||||
if (this.multicaster instanceof BeanFactoryAware) {
|
||||
((BeanFactoryAware) this.multicaster)
|
||||
.setBeanFactory(context.getBeanFactory());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextLoaded(ConfigurableApplicationContext context) {
|
||||
publishEvent(new ApplicationPreparedEvent(this.application, this.args, context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finished(ConfigurableApplicationContext context, Throwable exception) {
|
||||
if (exception != null) {
|
||||
publishEvent(new ApplicationFailedEvent(this.application, this.args, context,
|
||||
exception));
|
||||
}
|
||||
}
|
||||
|
||||
private void publishEvent(SpringApplicationEvent event) {
|
||||
this.multicaster.multicastEvent(event);
|
||||
}
|
||||
|
||||
}
|
@ -1,3 +1,7 @@
|
||||
# Run Participants
|
||||
org.springframework.boot.SpringApplicationRunParticipant=\
|
||||
org.springframework.boot.event.EventPublishingRunParticipant
|
||||
|
||||
# Application Context Initializers
|
||||
org.springframework.context.ApplicationContextInitializer=\
|
||||
org.springframework.boot.context.initializer.ContextIdApplicationContextInitializer,\
|
||||
|
Loading…
Reference in New Issue
Block a user