# Spring Boot 4.1.2 sources: the order SpringApplication.run() calls things in, and callRunners

--- SpringApplication.run(): from refresh to ready (lines containing the calls) ---
18: refreshContext(context);
19: afterRefresh(context, applicationArguments);
24: listeners.started(context, timeTakenToStarted);
25: callRunners(context, applicationArguments);
28: throw handleRunFailure(context, ex, listeners);
32: listeners.ready(context, startup.ready());
36: throw handleRunFailure(context, ex, null);

--- SpringApplication.callRunners ---
	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));
	}

--- SpringApplication.callRunner (what happens to a bean that is both kinds) ---
	private void callRunner(Runner runner, ApplicationArguments args) {
		if (runner instanceof ApplicationRunner) {
			callRunner(ApplicationRunner.class, runner, (applicationRunner) -> applicationRunner.run(args));
		}
		if (runner instanceof CommandLineRunner) {
			callRunner(CommandLineRunner.class, runner,
					(commandLineRunner) -> commandLineRunner.run(args.getSourceArgs()));
		}
	}

--- SpringApplication.callRunner(Class, Runner, ThrowingConsumer) (where 'Failed to execute' comes from) ---
	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);
	}

--- EventPublishingRunListener.started / ready ---
	public void started(ConfigurableApplicationContext context, @Nullable Duration timeTaken) {
		context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken));
		AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
	}
	public void ready(ConfigurableApplicationContext context, @Nullable Duration timeTaken) {
		context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, timeTaken));
		AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
	}

--- the marker interface that both runners extend ---
interface Runner {
public interface CommandLineRunner extends Runner {
public interface ApplicationRunner extends Runner {

--- the same method in Spring Boot 3.0.13 ---
	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);
			}
		});
	}

--- the same method in Spring Boot 3.1.12 ---
	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));
	}
