|
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