|
18 | 18 |
|
19 | 19 | import java.lang.StackWalker.StackFrame;
|
20 | 20 | import java.lang.management.ManagementFactory;
|
| 21 | +import java.lang.reflect.Method; |
21 | 22 | import java.time.Duration;
|
22 | 23 | import java.util.ArrayList;
|
23 | 24 | import java.util.Arrays;
|
24 | 25 | import java.util.Collection;
|
25 | 26 | import java.util.Collections;
|
| 27 | +import java.util.Comparator; |
26 | 28 | import java.util.HashMap;
|
| 29 | +import java.util.IdentityHashMap; |
27 | 30 | import java.util.LinkedHashSet;
|
28 | 31 | import java.util.List;
|
29 | 32 | import java.util.Map;
|
|
41 | 44 |
|
42 | 45 | import org.springframework.aot.AotDetector;
|
43 | 46 | import org.springframework.beans.BeansException;
|
| 47 | +import org.springframework.beans.factory.NoSuchBeanDefinitionException; |
44 | 48 | import org.springframework.beans.factory.config.BeanDefinition;
|
45 | 49 | import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
| 50 | +import org.springframework.beans.factory.config.ConfigurableBeanFactory; |
46 | 51 | import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
47 | 52 | import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader;
|
48 | 53 | import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
|
49 | 54 | import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
50 | 55 | import org.springframework.beans.factory.support.BeanNameGenerator;
|
51 | 56 | import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
| 57 | +import org.springframework.beans.factory.support.RootBeanDefinition; |
52 | 58 | import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
53 | 59 | import org.springframework.boot.Banner.Mode;
|
54 | 60 | import org.springframework.boot.context.properties.bind.Bindable;
|
|
74 | 80 | import org.springframework.context.support.AbstractApplicationContext;
|
75 | 81 | import org.springframework.context.support.GenericApplicationContext;
|
76 | 82 | import org.springframework.core.GenericTypeResolver;
|
| 83 | +import org.springframework.core.OrderComparator; |
| 84 | +import org.springframework.core.OrderComparator.OrderSourceProvider; |
77 | 85 | import org.springframework.core.Ordered;
|
78 | 86 | import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
79 | 87 | import org.springframework.core.annotation.Order;
|
@@ -762,35 +770,42 @@ protected void refresh(ConfigurableApplicationContext applicationContext) {
|
762 | 770 | protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
|
763 | 771 | }
|
764 | 772 |
|
765 |
| - private void callRunners(ApplicationContext context, ApplicationArguments args) { |
766 |
| - context.getBeanProvider(Runner.class).orderedStream().forEach((runner) -> { |
767 |
| - if (runner instanceof ApplicationRunner applicationRunner) { |
768 |
| - callRunner(applicationRunner, args); |
769 |
| - } |
770 |
| - if (runner instanceof CommandLineRunner commandLineRunner) { |
771 |
| - callRunner(commandLineRunner, args); |
772 |
| - } |
773 |
| - }); |
| 773 | + private void callRunners(ConfigurableApplicationContext context, ApplicationArguments args) { |
| 774 | + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); |
| 775 | + String[] beanNames = beanFactory.getBeanNamesForType(Runner.class); |
| 776 | + Map<Runner, String> instancesToBeanNames = new IdentityHashMap<>(); |
| 777 | + for (String beanName : beanNames) { |
| 778 | + instancesToBeanNames.put(beanFactory.getBean(beanName, Runner.class), beanName); |
| 779 | + } |
| 780 | + Comparator<Object> comparator = getOrderComparator(beanFactory) |
| 781 | + .withSourceProvider(new FactoryAwareOrderSourceProvider(beanFactory, instancesToBeanNames)); |
| 782 | + instancesToBeanNames.keySet().stream().sorted(comparator).forEach((runner) -> callRunner(runner, args)); |
774 | 783 | }
|
775 | 784 |
|
776 |
| - private void callRunner(ApplicationRunner runner, ApplicationArguments args) { |
777 |
| - try { |
778 |
| - (runner).run(args); |
779 |
| - } |
780 |
| - catch (Exception ex) { |
781 |
| - throw new IllegalStateException("Failed to execute ApplicationRunner", ex); |
782 |
| - } |
| 785 | + private OrderComparator getOrderComparator(ConfigurableListableBeanFactory beanFactory) { |
| 786 | + Comparator<?> dependencyComparator = (beanFactory instanceof DefaultListableBeanFactory defaultListableBeanFactory) |
| 787 | + ? defaultListableBeanFactory.getDependencyComparator() : null; |
| 788 | + return (dependencyComparator instanceof OrderComparator orderComparator) ? orderComparator |
| 789 | + : AnnotationAwareOrderComparator.INSTANCE; |
783 | 790 | }
|
784 | 791 |
|
785 |
| - private void callRunner(CommandLineRunner runner, ApplicationArguments args) { |
786 |
| - try { |
787 |
| - (runner).run(args.getSourceArgs()); |
| 792 | + private void callRunner(Runner runner, ApplicationArguments args) { |
| 793 | + if (runner instanceof ApplicationRunner) { |
| 794 | + callRunner(ApplicationRunner.class, runner, (applicationRunner) -> applicationRunner.run(args)); |
788 | 795 | }
|
789 |
| - catch (Exception ex) { |
790 |
| - throw new IllegalStateException("Failed to execute CommandLineRunner", ex); |
| 796 | + if (runner instanceof CommandLineRunner) { |
| 797 | + callRunner(CommandLineRunner.class, runner, |
| 798 | + (commandLineRunner) -> commandLineRunner.run(args.getSourceArgs())); |
791 | 799 | }
|
792 | 800 | }
|
793 | 801 |
|
| 802 | + @SuppressWarnings("unchecked") |
| 803 | + private <R extends Runner> void callRunner(Class<R> type, Runner runner, ThrowingConsumer<R> call) { |
| 804 | + call.throwing( |
| 805 | + (message, ex) -> new IllegalStateException("Failed to execute " + ClassUtils.getShortName(type), ex)) |
| 806 | + .accept((R) runner); |
| 807 | + } |
| 808 | + |
794 | 809 | private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
|
795 | 810 | SpringApplicationRunListeners listeners) {
|
796 | 811 | try {
|
@@ -1636,8 +1651,8 @@ public SpringApplicationRunListener getRunListener(SpringApplication springAppli
|
1636 | 1651 | }
|
1637 | 1652 |
|
1638 | 1653 | /**
|
1639 |
| - * Starts a non-daemon thread to keep the JVM alive on {@link ContextRefreshedEvent}. |
1640 |
| - * Stops the thread on {@link ContextClosedEvent}. |
| 1654 | + * <<<<<<< HEAD Starts a non-daemon thread to keep the JVM alive on |
| 1655 | + * {@link ContextRefreshedEvent}. Stops the thread on {@link ContextClosedEvent}. |
1641 | 1656 | */
|
1642 | 1657 | private static final class KeepAlive implements ApplicationListener<ApplicationContextEvent> {
|
1643 | 1658 |
|
@@ -1774,4 +1789,41 @@ String action() {
|
1774 | 1789 |
|
1775 | 1790 | }
|
1776 | 1791 |
|
| 1792 | + /** |
| 1793 | + * {@link OrderSourceProvider} used to obtain factory method and target type order |
| 1794 | + * sources. Based on internal {@link DefaultListableBeanFactory} code. |
| 1795 | + */ |
| 1796 | + private class FactoryAwareOrderSourceProvider implements OrderSourceProvider { |
| 1797 | + |
| 1798 | + private final ConfigurableBeanFactory beanFactory; |
| 1799 | + |
| 1800 | + private final Map<?, String> instancesToBeanNames; |
| 1801 | + |
| 1802 | + FactoryAwareOrderSourceProvider(ConfigurableBeanFactory beanFactory, Map<?, String> instancesToBeanNames) { |
| 1803 | + this.beanFactory = beanFactory; |
| 1804 | + this.instancesToBeanNames = instancesToBeanNames; |
| 1805 | + } |
| 1806 | + |
| 1807 | + @Override |
| 1808 | + public Object getOrderSource(Object obj) { |
| 1809 | + String beanName = this.instancesToBeanNames.get(obj); |
| 1810 | + return (beanName != null) ? getOrderSource(beanName, obj.getClass()) : null; |
| 1811 | + } |
| 1812 | + |
| 1813 | + private Object getOrderSource(String beanName, Class<?> instanceType) { |
| 1814 | + try { |
| 1815 | + RootBeanDefinition beanDefinition = (RootBeanDefinition) this.beanFactory |
| 1816 | + .getMergedBeanDefinition(beanName); |
| 1817 | + Method factoryMethod = beanDefinition.getResolvedFactoryMethod(); |
| 1818 | + Class<?> targetType = beanDefinition.getTargetType(); |
| 1819 | + targetType = (targetType != instanceType) ? targetType : null; |
| 1820 | + return Stream.of(factoryMethod, targetType).filter(Objects::nonNull).toArray(); |
| 1821 | + } |
| 1822 | + catch (NoSuchBeanDefinitionException ex) { |
| 1823 | + return null; |
| 1824 | + } |
| 1825 | + } |
| 1826 | + |
| 1827 | + } |
| 1828 | + |
1777 | 1829 | }
|
0 commit comments