|
1 | 1 | /* |
2 | | - * Copyright 2012-2024 the original author or authors. |
| 2 | + * Copyright 2012-2025 the original author or authors. |
3 | 3 | * |
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | 5 | * you may not use this file except in compliance with the License. |
|
19 | 19 | import java.lang.reflect.Method; |
20 | 20 | import java.util.ArrayList; |
21 | 21 | import java.util.Arrays; |
| 22 | +import java.util.Collection; |
22 | 23 | import java.util.Collections; |
23 | 24 | import java.util.List; |
24 | 25 | import java.util.function.Consumer; |
25 | 26 |
|
| 27 | +import org.springframework.aot.generate.GenerationContext; |
| 28 | +import org.springframework.aot.hint.ExecutableMode; |
| 29 | +import org.springframework.aot.hint.ReflectionHints; |
26 | 30 | import org.springframework.beans.BeanUtils; |
| 31 | +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; |
| 32 | +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; |
| 33 | +import org.springframework.beans.factory.aot.BeanFactoryInitializationCode; |
| 34 | +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; |
27 | 35 | import org.springframework.boot.ApplicationContextFactory; |
28 | 36 | import org.springframework.boot.Banner; |
29 | 37 | import org.springframework.boot.ConfigurableBootstrapContext; |
@@ -158,20 +166,23 @@ private Method getMainMethod(MergedContextConfiguration mergedConfig, UseMainMet |
158 | 166 | .orElse(null); |
159 | 167 | Assert.state(springBootConfiguration != null || useMainMethod == UseMainMethod.WHEN_AVAILABLE, |
160 | 168 | "Cannot use main method as no @SpringBootConfiguration-annotated class is available"); |
161 | | - Method mainMethod = (springBootConfiguration != null) |
162 | | - ? ReflectionUtils.findMethod(springBootConfiguration, "main", String[].class) : null; |
| 169 | + Method mainMethod = findMainMethod(springBootConfiguration); |
| 170 | + Assert.state(mainMethod != null || useMainMethod == UseMainMethod.WHEN_AVAILABLE, |
| 171 | + () -> "Main method not found on '%s'".formatted(springBootConfiguration.getName())); |
| 172 | + return mainMethod; |
| 173 | + } |
| 174 | + |
| 175 | + private static Method findMainMethod(Class<?> type) { |
| 176 | + Method mainMethod = (type != null) ? ReflectionUtils.findMethod(type, "main", String[].class) : null; |
163 | 177 | if (mainMethod == null && KotlinDetector.isKotlinPresent()) { |
164 | 178 | try { |
165 | | - Class<?> kotlinClass = ClassUtils.forName(springBootConfiguration.getName() + "Kt", |
166 | | - springBootConfiguration.getClassLoader()); |
| 179 | + Class<?> kotlinClass = ClassUtils.forName(type.getName() + "Kt", type.getClassLoader()); |
167 | 180 | mainMethod = ReflectionUtils.findMethod(kotlinClass, "main", String[].class); |
168 | 181 | } |
169 | 182 | catch (ClassNotFoundException ex) { |
170 | 183 | // Ignore |
171 | 184 | } |
172 | 185 | } |
173 | | - Assert.state(mainMethod != null || useMainMethod == UseMainMethod.WHEN_AVAILABLE, |
174 | | - () -> "Main method not found on '%s'".formatted(springBootConfiguration.getName())); |
175 | 186 | return mainMethod; |
176 | 187 | } |
177 | 188 |
|
@@ -574,4 +585,39 @@ private ApplicationContext run(ThrowingSupplier<ConfigurableApplicationContext> |
574 | 585 |
|
575 | 586 | } |
576 | 587 |
|
| 588 | + static class MainMethodBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor { |
| 589 | + |
| 590 | + @Override |
| 591 | + public BeanFactoryInitializationAotContribution processAheadOfTime( |
| 592 | + ConfigurableListableBeanFactory beanFactory) { |
| 593 | + List<Method> mainMethods = new ArrayList<>(); |
| 594 | + for (String beanName : beanFactory.getBeanDefinitionNames()) { |
| 595 | + Class<?> beanType = beanFactory.getType(beanName); |
| 596 | + Method mainMethod = findMainMethod(beanType); |
| 597 | + if (mainMethod != null) { |
| 598 | + mainMethods.add(mainMethod); |
| 599 | + } |
| 600 | + } |
| 601 | + return !mainMethods.isEmpty() ? new AotContribution(mainMethods) : null; |
| 602 | + } |
| 603 | + |
| 604 | + static class AotContribution implements BeanFactoryInitializationAotContribution { |
| 605 | + |
| 606 | + private final Collection<Method> mainMethods; |
| 607 | + |
| 608 | + AotContribution(Collection<Method> mainMethods) { |
| 609 | + this.mainMethods = mainMethods; |
| 610 | + } |
| 611 | + |
| 612 | + @Override |
| 613 | + public void applyTo(GenerationContext generationContext, |
| 614 | + BeanFactoryInitializationCode beanFactoryInitializationCode) { |
| 615 | + ReflectionHints reflectionHints = generationContext.getRuntimeHints().reflection(); |
| 616 | + this.mainMethods.forEach((method) -> reflectionHints.registerMethod(method, ExecutableMode.INVOKE)); |
| 617 | + } |
| 618 | + |
| 619 | + } |
| 620 | + |
| 621 | + } |
| 622 | + |
577 | 623 | } |
0 commit comments