@ -17,12 +17,15 @@
@@ -17,12 +17,15 @@
package org.springframework.boot ;
import java.lang.StackWalker.StackFrame ;
import java.lang.reflect.Method ;
import java.time.Duration ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.Collection ;
import java.util.Collections ;
import java.util.Comparator ;
import java.util.HashMap ;
import java.util.IdentityHashMap ;
import java.util.LinkedHashSet ;
import java.util.List ;
import java.util.Map ;
@ -38,14 +41,17 @@ import org.apache.commons.logging.LogFactory;
@@ -38,14 +41,17 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.aot.AotDetector ;
import org.springframework.beans.BeansException ;
import org.springframework.beans.factory.NoSuchBeanDefinitionException ;
import org.springframework.beans.factory.config.BeanDefinition ;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor ;
import org.springframework.beans.factory.config.ConfigurableBeanFactory ;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory ;
import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader ;
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory ;
import org.springframework.beans.factory.support.BeanDefinitionRegistry ;
import org.springframework.beans.factory.support.BeanNameGenerator ;
import org.springframework.beans.factory.support.DefaultListableBeanFactory ;
import org.springframework.beans.factory.support.RootBeanDefinition ;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader ;
import org.springframework.boot.Banner.Mode ;
import org.springframework.boot.context.properties.bind.Bindable ;
@ -68,6 +74,8 @@ import org.springframework.context.aot.AotApplicationContextInitializer;
@@ -68,6 +74,8 @@ import org.springframework.context.aot.AotApplicationContextInitializer;
import org.springframework.context.support.AbstractApplicationContext ;
import org.springframework.context.support.GenericApplicationContext ;
import org.springframework.core.GenericTypeResolver ;
import org.springframework.core.OrderComparator ;
import org.springframework.core.OrderComparator.OrderSourceProvider ;
import org.springframework.core.Ordered ;
import org.springframework.core.annotation.AnnotationAwareOrderComparator ;
import org.springframework.core.annotation.Order ;
@ -746,35 +754,42 @@ public class SpringApplication {
@@ -746,35 +754,42 @@ public class SpringApplication {
protected void afterRefresh ( ConfigurableApplicationContext context , ApplicationArguments args ) {
}
private void callRunners ( ApplicationContext context , ApplicationArguments args ) {
context . getBeanProvider ( Runner . class ) . orderedStream ( ) . forEach ( ( runner ) - > {
if ( runner instanceof ApplicationRunner applicationRunner ) {
callRunner ( applicationRunner , args ) ;
}
if ( runner instanceof CommandLineRunner commandLineRunner ) {
callRunner ( commandLineRunner , args ) ;
}
} ) ;
private void callRunners ( ConfigurableApplicationContext context , ApplicationArguments args ) {
ConfigurableListableBeanFactory beanFactory = context . getBeanFactory ( ) ;
String [ ] beanNames = beanFactory . getBeanNamesForType ( Runner . class ) ;
Map < Runner , String > instancesToBeanNames = new IdentityHashMap < > ( ) ;
for ( String beanName : beanNames ) {
instancesToBeanNames . put ( beanFactory . getBean ( beanName , Runner . class ) , beanName ) ;
}
Comparator < Object > comparator = getOrderComparator ( beanFactory )
. withSourceProvider ( new FactoryAwareOrderSourceProvider ( beanFactory , instancesToBeanNames ) ) ;
instancesToBeanNames . keySet ( ) . stream ( ) . sorted ( comparator ) . forEach ( ( runner ) - > callRunner ( runner , args ) ) ;
}
private void callRunner ( ApplicationRunner runner , ApplicationArguments args ) {
try {
( runner ) . run ( args ) ;
}
catch ( Exception ex ) {
throw new IllegalStateException ( "Failed to execute ApplicationRunner" , ex ) ;
}
private OrderComparator getOrderComparator ( ConfigurableListableBeanFactory beanFactory ) {
Comparator < ? > dependencyComparator = ( beanFactory instanceof DefaultListableBeanFactory defaultListableBeanFactory )
? defaultListableBeanFactory . getDependencyComparator ( ) : null ;
return ( dependencyComparator instanceof OrderComparator orderComparator ) ? orderComparator
: AnnotationAwareOrderComparator . INSTANCE ;
}
private void callRunner ( CommandLine Runner runner , ApplicationArguments args ) {
try {
( runner ) . run ( args . getSourceArgs ( ) ) ;
private void callRunner ( Runner runner , ApplicationArguments args ) {
if ( runner instanceof ApplicationRunner ) {
callRunner ( ApplicationRunner . class , runner , ( applicationRunner ) - > applicationRunner . run ( args ) ) ;
}
catch ( Exception ex ) {
throw new IllegalStateException ( "Failed to execute CommandLineRunner" , ex ) ;
if ( runner instanceof CommandLineRunner ) {
callRunner ( CommandLineRunner . class , runner ,
( commandLineRunner ) - > commandLineRunner . run ( args . getSourceArgs ( ) ) ) ;
}
}
@SuppressWarnings ( "unchecked" )
private < R extends Runner > void callRunner ( Class < R > type , Runner runner , ThrowingConsumer < R > call ) {
call . throwing (
( message , ex ) - > new IllegalStateException ( "Failed to execute " + ClassUtils . getShortName ( type ) , ex ) )
. accept ( ( R ) runner ) ;
}
private void handleRunFailure ( ConfigurableApplicationContext context , Throwable exception ,
SpringApplicationRunListeners listeners ) {
try {
@ -1598,4 +1613,41 @@ public class SpringApplication {
@@ -1598,4 +1613,41 @@ public class SpringApplication {
}
/ * *
* { @link OrderSourceProvider } used to obtain factory method and target type order
* sources . Based on internal { @link DefaultListableBeanFactory } code .
* /
private class FactoryAwareOrderSourceProvider implements OrderSourceProvider {
private final ConfigurableBeanFactory beanFactory ;
private final Map < ? , String > instancesToBeanNames ;
FactoryAwareOrderSourceProvider ( ConfigurableBeanFactory beanFactory , Map < ? , String > instancesToBeanNames ) {
this . beanFactory = beanFactory ;
this . instancesToBeanNames = instancesToBeanNames ;
}
@Override
public Object getOrderSource ( Object obj ) {
String beanName = this . instancesToBeanNames . get ( obj ) ;
return ( beanName ! = null ) ? getOrderSource ( beanName , obj . getClass ( ) ) : null ;
}
private Object getOrderSource ( String beanName , Class < ? > instanceType ) {
try {
RootBeanDefinition beanDefinition = ( RootBeanDefinition ) this . beanFactory
. getMergedBeanDefinition ( beanName ) ;
Method factoryMethod = beanDefinition . getResolvedFactoryMethod ( ) ;
Class < ? > targetType = beanDefinition . getTargetType ( ) ;
targetType = ( targetType ! = instanceType ) ? targetType : null ;
return Stream . of ( factoryMethod , targetType ) . filter ( Objects : : nonNull ) . toArray ( ) ;
}
catch ( NoSuchBeanDefinitionException ex ) {
return null ;
}
}
}
}